let 指令用法类似于 var,也是用来声明变量 ,但是它所声明的变量,只能在 let 指令所在的代码块内有效 。
{
let a = 1;
var b = 1;
}
console.log(b);
console.log(a);
运行结果:
1
console.log(a);
^
ReferenceError: a is not defined
此例中, b 会打印出结果。但 a 因为是使用 let 命令声明的变量,所以只在它所在的代码块内有效。
1 应用场景
let 指令适用于 for 循环变量声明。在 ES6 之前,我们使用 var 指令来声明变量,可能存在一些问题,请看下面的示例:
var a = [];
for (var i = 0; i < 3; i++) {
a[i] = function () {
console.log(i);
};
}
a[0]()
a[2]()
运行结果:
3
3
变量 i 是 var 声明的,所以它在全局范围内都有效 。 所以在每一次循环中,新的 i 值都会覆盖旧值,导致最后 a 中的所有函数,输出的都是最后一轮的 i 的值 。
使用 let 指令,就能够避免上述问题:
var a = [];
for (let i = 0; i < 3; i++) {
a[i] = function () {
console.log(i);
};
}
a[0]()
a[2]()
运行结果:
0
2
注意: for 循环内部,设置循环变量是一个作用域,而循环体内部是另一个作用域:
for (let i = 0; i < 3; i++) {
let i = 10;
console.log(i)
}
运行结果:
10
10
10
2 变量不提升
var 会发生 “ 变量提升 ” 现象,即 var 声明的变量,可以在声明之前使用。 但 let 声明的变量,一定要在声明之后使用,这种设计,让 JS 变得更加规范。变量在声明后,才能使用。
//var 变量提升
console.log('j='+j);
var j = 1;
//let 变量不会提升
console.log('k='+k);
let k = 1;
运行结果:
j=undefined
ReferenceError: k is not defined
3 暂时性死区
只要块级作用域内,存在 let 指令,那么它所声明的变量不会再受外部影响,所以称为暂时性死区(temporal dead zone)。
var str = 1;
if (true) {
str = 'a';
let str;
}
运行结果:
ReferenceError: str is not defined
ES6 中,如果代码块内存在 let 或 const 指令声明的变量,那么这些变量从一开始就会形成封闭作用域 。 凡在声明之前使用这些变量,就会抛出 ReferenceError。
3.1 对 typeof 的影响
暂时性死区甚至会影响到 typeof 操作符:
if(true){
console.log('y 类型:'+typeof y);
console.log('x 类型:'+typeof x);
let x;
}
运行结果:
y 类型:undefined
ReferenceError: x is not defined
这个示例,变量 x 使用 let 指令声明,所以在声明之前,都属于 x 的暂时性死区 ,因此抛出了 ReferenceError 。
3.2 隐蔽的死区
请看这个示例:
function test(x = y, y = 1) {
return x + y;
}
test();
运行结果:
ReferenceError: y is not defined
函数的入参 x,它的默认值等于另一个入参 y ,而此时 y 还未声明,所以会抛出 ReferenceError。
只要声明了所有的入参,就可以让这个函数正确运行:
function test2(y = 1,x = y ) {
return x + y;
}
console.log(test2());
运行结果:
2
暂时性死区的设定,可以有效地减少运行时错误。它的本质是:在当前作用域下,只有声明了变量,才可以使用它。
4 拒绝重复声明
let 指令,在相同作用域内,同一个变量只能被声明一次。
if(true){
let a = 1;
var a = 2;
}
运行结果:
SyntaxError: Identifier 'a' has already been declared
if(true){
let a = 1;
let a = 2;
}
运行结果与上例相同。
这样的限制,也约束了函数的入参声明:
function test(a) {
let a = 2;
console.log(a);
}
test(1);
运行结果:
SyntaxError: Identifier 'a' has already been declared
但我们可以在函数内部,加入块级作用域,来绕开这一限制:
function test(a) {
{
let a = 2;
console.log(a);
}
}
test(1);
运行结果:
2
网友评论