let 和 const 新增了块级作用域

1
2
3
4
5
6
7
8
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[0]();//10
a[6](); // 10

使用var来定义变量的时候,下面的例子会全部输出 10,要解决该问题,可以使用闭包

1
2
3
4
5
6
7
8
9
10
var a = [];
for (var i = 0; i < 10; i++){
a[i] = (function(a) {
return function() {
console.log(a)
}
})(i)
}
a[6](); // 6
a[9](); // 9

现在,我们可以用let来解决这个问题

1
2
3
4
5
6
7
8
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[0]();//0
a[6](); // 6

因为let每次循环都会生成一个新的块级作用域,内部保存着i变量的值。

let 和 const 不会变量提升,不允许重复定义变量,并且存在TDZ(暂时性死区)

1
2
3
4
console.log(a);
console.log(b);
var a=0; // undefined
let b=0; // ReferenceError: b is not defined

在块级作用域中,即使不存在变量提升,它也会影响当前块级作用域,即绑定在了当前作用域。在作用域中引用外部的变量将会报错。

const 用来定义常量

const 实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const 只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了

1
2
3
const a=[1,2,3]
a.push(4)
console.log(a); //[1, 2, 3, 4]