在ES6之前,都是使用var来声明变量
要声明变量需要在var后面跟上一个变量名,如:
var a;
这段代码通过var声明了一个名字为a的变量,它可以保存任意的数据类型,因为没有给他赋值,他的值默认为undefined。
可以在声明变量的时候直接赋值,如:
var a = 123;
var b = '你好';
这段代码声明了变量a,赋值为Number类型的123和声明了变量b赋值为String类型的你好。
1. 全局变量
通过var声明的全局变量,是在window对象中的,如:
var a = 1;
console.log(a); // 1
console.log(window.a); // 1
2. 局部变量
也可以在函数内部中声明变量,这样他就会成为函数的局部变量,在函数退出时变量会被销毁,如:
function a() {
var b = 123;
console.log(b); // 123
}
a();
console.log(b); // 出错,会提示b没有定义。
在上面代码中,在a函数内部中声明了一个变量b,在执行完函数后,变量b会被销毁,所以最后一句代码会报错,提示b没有定义。
3. 其他
在函数内,是可以访问全局变量的,如:
var num = 123;
function a() {
console.log(num); // 123
}
a();
在全局变量和局部变量名相同的情况下,会优先使用最近作用域当中的局部变量,如果当前作用域中没有这个变量,那么它会向上一层层的作用域中寻找,直到找到变量为止,如果到了window对象还没有这个变量,那么会报错,如:
var num = 123; // 全局变量
function a() {
var num = 222; // 局部变量
console.log(num); // 222 输出的局部变量
}
function b() {
console.log(num); // 123 输出的全局变量
}
function c() {
console.log(xx); // 报错 没有找到这个变量
}
a();
b();
c();
上面代码,有一个全局变量num,函数a中,因为也声明了局部变量名叫num,所以函数a中输出的是222。函数b中,没有名为num的局部变量,所以向上寻找,直到在全局变量中找到了num,输出为123。函数c中,并没有声明局部变量xx,向上寻找也未寻找到名为xx的变量,所以会报错,提示变量xx未定义。
function a() {
console.log(b);
var b = 123;
console.log(b);
}
a();
看到这段代码,第一反应是,函数a中的第一句console.log(b);肯定会报错,因为变量b是在这一句的下面才声明的,而且全局变量中也没有b,其实并不是这样的,因为通过var声明的变量会自动把声明都放在作用域的最顶部,同等于以下代码:
function a() {
var b;
console.log(b); // undefined
b = 123;
console.log(b); // 123
}
a();
函数a中,第一句就直接声明了变量b,没有给他赋值,所以第一句输出语句输出的值是undefined,在下面才给它赋值为123,所以第二句输出语句输出的值为123。
let是es6中新出的声明变量的关键字,他和var基本上一样,但是也有一些区别。
这是一个块级作用域的例子:
if (true) {
var a = 11;
let b = 22;
console.log(a); // 11
console.log(b); // 22
}
console.log(a); // 11
console.log(b); // 报错 没有定义
首先可以看到,if代码块中通过var和let各声明了一个变量a和b。
a因为是通过var声明的,是函数作用域,然而if并不是函数,所以a会成为全局变量,所以if中和下面的代码输出a的值都为11。
b通过let声明,在if代码块中属于局部变量,作用域只在if代码块中,所以if代码块中输出b的值为22,最下面输出b的值会报错。
再看一个let没有变量提升的例子:
function a() {
console.log(b); // Cannot access 'b' before initialization
let b = 11;
}
a();
a函数中,在声明b之前输出b值,报错提示不能在声明b之前使用b,代表了let声明的变量是没有变量提升的。
let声明的全局变量不在window对象中例子:
var a = 1;
let b = 2;
console.log(window.a); // 1
console.log(window.b); // undefined
可以看到,通过var声明的变量是在window对象中的,通过let声明的变量不在window中,所以输出结果为undefined。
const也是es6新出的一种声明变量的关键字,它和let基本上一样,但是也有一些区别。
通过const声明变量的时候必须赋值,看一个例子:
const a; // 报错 Missing initializer in const declaration
const a = 1; // 正确
不能修改const的值,例子:
const a = 1;
a = 2; // 报错 Assignment to constant variable.
注意、注意、注意、 不能修改const的值是指的不修改他的指向的变量的引用,如果你的值是一个对象,那么是可以修改这个对象的内部属性的,因为他的指向没有变,例如:
const a = {
b: 2,
}
a.b = 3
const c = {
}
c = {
} // 报错 Assignment to constant variable.
这个例子声明了一个对象a,并且修改了它的内部属性b,a的指向没有变,这样并不违反const的规则。
下面还声明了一个对象c,并且重新给他赋值了一个对象,这样指向会改变,违反了const规则并报错。
有些人可能会懵了,3个到底要用哪一个?
根据现在的开发者普遍的情况,总结如下: