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
来源: http://www.jianshu.com/p/a3137b8951f1