前言
1、let / const 和 var 的区别
想必涉及let / const 最多的问题就是 它们和 var的区别了,一般的解答是这样的:
- let / const 声明的变量的作用域是块级的,var 声明的变量的作用域是全局的;
- let / const 不能重复声明已存在的变量,var 可以重复声明已存在的变量;
- var 不能限制对变量的修改,const 声明的变量不能修改;
- let / const 有暂时死区,不能提升。
2、特殊情况
for(var i=0; i<10;i++){
setTimeout(function(){
console.log(i)
}, 0)
}
// 打印结果为 10个 10,原因都知道,就不多解释了
但是 将 var 改为 let 后,结果就不一样了
for(let i=0; i<10;i++){
setTimeout(function(){
console.log(i)
}, 0)
}
// 打印结果: 0 1 2 3 4 5 6 7 8 9
这是为什么呢? for 循环头部的 let 不仅将 i 绑定到了 for 循环的块中,事实上它将其重新绑定到了循环 的每一个迭代中,确保使用上一个循环迭代结束时的值重新进行赋值,相当于每次循环都重新建了一个作用域。 可以这样理解:
for(var i=0; i<10;i++){
let j= i;
setTimeout(function(){
console.log(j)
}, 0)
}
// 打印结果: 0 1 2 3 4 5 6 7 8 9
关于暂时死区,是什么原因呢,为什么 var 声明的变量却没有呢?
{
console.log(x);
let x
}
{
console.log(x);
const x
}
// 这两个都会报一样的错
// Uncaught ReferenceError: Cannot access 'x' before initialization
// x 被初始化之前不能使用
// 但是使用var 声明却不会报错
{
console.log(x);
var x
}
// undefined
报错的内容是 “初始化之前不能使用”,那么这就涉及到了变量的声明过程了:
函数、变量声明的过程:创建、初始化、赋值
1、function 声明的「创建、初始化和赋值」过程
fn2()
function fn2(){
console.log(2)
}
- 找到所有用 function 声明的变量,在环境中「创建」这些变量。
- 将这些变量「初始化」并「赋值」为 function(){ console.log(2) }。
- 开始执行代码 fn2() 也就是说 function 声明的代码, 在执行代码之前就已经 【创建、初始化、赋值】了。
2、var 声明【创建、初始化、赋值】的过程:
- 找到用 var 声明的变量, 在环境中 【创建】这些变量;
- 将这些变量【初始化】 为 undefined;
- 执行代码
- 给变量赋值
3、let / const 声明【创建、初始化、赋值】的过程:
{
let x = 1
x = 2
}
- 找到 let / const 声明的变量,在环境中 【创建】这些变量;
- 执行代码(注意现在还没有初始化,这是最重要的一点);
- 执行 x=1,将 x 【初始化】为1,(注意此处不是赋值,如果是 let x; 则将 x 初始化为 undefined)
- 执行 x =2;对 x 进行【赋值】
那么 let / const 出现暂时性死区的原因是:
{
console.log(x);
let x
}
- 首先这段代码同属于一个块级作用域
- 这个作用域内部声明了 x 这个变量,所以在执行 语句console.log(x) 时,这个 x 就是块内部的 x , 不是外部的 x
- 但是因为 let / const 声明变量的过程中只提升了创建部分,没有进行初始化,此时只是创建了 x ,还没有初始化,所以不能使用。
关于变量提升的总结:
- let / const 的「创建」过程被提升了,但是 【初始化】过程 没有提升。
- var 的「创建」和「初始化」都被提升了。
- function 的「创建」「初始化」和「赋值」都被提升了。