变量
var与变量提升
使用var
关键字声明的变量,无论其声明位置在哪里,都会被视为声明于所在函数的顶部。如果声明不在函数内,则被视为在全局作用域的顶部。这就是变量提升。
function getValue1(condition){
if(condition){
var value = 'v';
return value;
}else {
console.log(value)
return null;
}
}
getValue1(false)
// output:undefined
可以看出在var
在else
中可以调用,说明已经创建了 value
console.log(value);
var value = 10;
// undefined
块级声明
块级声明:让所声明的变量在指定块的作用域外无法被访问。
块级作用域在以下情况被创建
- 在一个函数内部
- 在一个代码块内部(
{}
包裹)
let声明
再看一个例子,如果使用的是 let
的话
function getValue2(condition){
if(condition){
let value = 'v';
return value;
}else {
console.log(value)
return null;
}
}
getValue2(false);
上述代码会直接报错。ReferenceError: value is not defined
禁止重复声明
在同一个块级声明中 let
声明的变量是唯一的。
var value = 'a';
let value = 'b';
// 报错
var value = 'a';
if (condition) {
let value = 'b'
}
// 不会报错,括号内的value,会在其块级作用域内屏蔽对外部value的访问
const常量声明
使用const
声明的变量是不可修改的,而且在声明时就需要完成初始化。
const value = 10;
// value声明、初始化后就不可修改
const demo;
demo = 10;
// error
对比const和let
与let
相似,const
也是禁止重复声明的,且其作用域在块级声明内部。
const声明对象
const
声明会阻止对于变量绑定与变量自身值的修改,但是对于变量成员的修改是可以的。
其实也很容易理解,对象是个引用,const person
绑定的引用不可变化,但是其指针指向的值可以变化。
const person = {
age: 10
}
person.age = 20;
// 可以执行
person = {
age: 20
}
// error
暂时性死区
暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,处于暂时性死区内(TDZ),只有等到声明变量的那一行代码出现,才可以获取和使用该变量。
看一个例子:
var tmp = 123;
if (true) {
typeof tmp;
let tmp;
}
在进入块级作用域后,tmp
就已经存在了,并且屏蔽了对于外部var tmp
的访问,此时 tmp
在暂时性死区中,处于不可访问的状态,所以typeof tmp
报错。
再看一个例子:
if (true) {
typeof tmp;// 依旧会报错
let tmp;
}
如果在块级作用域内没有声明:
if (true) {
typeof tmp;
}
// 可以正常运行不报错
循环中的块级绑定
首先,循环内部定义的 var
在循环外部可以访问,let
不能访问。
循环内的函数
let
var test = []
for (let i = 0; i < 10; i++) {
test.push(function(){console.log(i)})
}
test[3]()
// output: 3
var
var test = []
for (var i = 0; i < 10; i++) {
test.push(function(){console.log(i)})
}
test[3]()
// output: 10
const
var funcs = [];
// 在一次迭代后抛出错误
for (const i = 0; i < 10; i++) {
funcs.push(function() {
console.log(i);
});
}
var funcs = [],
object = {
a: true,
b: true,
c: true
};
// 不会导致错误
for (const key in object) {
funcs.push(function() {
console.log(key);
});
}
funcs.forEach(function(func) {
func();
// 依次输出 "a"、 "b"、 "c"
});
当使用for-in
和for-of
的时候,实际上const
没有发生值的改变,所以不会报错。
块级绑定的最佳实践
在ES6
的发展过程中,广泛认可的变量声明方法是:
- 默认使用
const
- 对于需要变动的变量使用
let