# let, const, var
# 变量提升
当你使用var
去定义变量时, 在编译 JS 时变量会全部提升到当前作用域的顶部.
同时在全局作用域定义的变量都会成为window
的属性
# 作用域
# ES6 之前
只有全局作用域和函数作用域
# ES6 之后
全局作用域 和 函数作用域 和 块级作用域
# 创建块级作用域
ES6 后新增了块级作用域, 用{}
括住:
{
let x = 1;
}
console.log(x); // Uncaught ReferenceError: x is not defined
1
2
3
4
2
3
4
块级作用域内的变量不能被外部作用域调用, 而let
/const
的特点之一就是声明之后便创建一个块级作用域.
# 从for
循环看let
与var
的区别
使用var
:
for (var i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i);
}, 1000);
}
5;
5;
5;
5;
5;
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
使用let
:
for (let i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i);
}, 1000);
}
0;
1;
2;
3;
4;
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# Analysis
当用var
声明i
时, 进行异步循环打出了 5 个5
, 实际上是在异步开始后执行()
里的代码:
var i = 0;
// i < 5 满足
i = 1;
i = 2;
i = 3;
i = 4;
i = 5;
// i < 5 不满足
console.log(i);
console.log(i);
console.log(i);
console.log(i);
console.log(i);
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
当用let
声明i
时, 情况也将大不相同, 从别人的文章里发现.let
有两个很有特点的地方:
for( let i = 0; i< 5; i++)
这句话的圆括号之间,有一个隐藏的作用域for( let i = 0; i< 5; i++) { 循环体 }
在每次执行循环体之前,JS 引擎会把i
在循环体的上下文中重新声明及初始化一次。
用代码来表述就是:
{
let i = 0;
console.log(i);
}
{
let i = 1; // for循环会记住上次循环结果并赋值给下个循环
console.log(i);
}
{
let i = 2;
console.log(i);
}
{
let i = 3;
console.log(i);
}
{
let i = 4;
console.log(i);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Temporary Dead Zone
{
console.log(x);
let x = 1;
}
// Uncaught ReferenceError: Cannot access 'x' before initialization
1
2
3
4
5
2
3
4
5
报错的意思是不能在初始化之前访问, let
/const
的特点就是在创建(created)前的任何操作(访问, 初始化, 赋值)都是不被允许的.而在被创建的之前的部分叫做暂时性死区(Temporary Dead Zone, TDZ).
探究 TDZ 的原理时, 我们也发现了let
/const
也会提升的事实, 但和var
的提升大不相同:
var
在创建(created)时就被初始化(initialize)为undefined
let
/const
在进入块级作用域后,会因为提升的原因先创建,但不会被初始化,直到声明语句执行的时候才被初始化,初始化的时候如果使用let
声明的变量没有赋值,则会默认赋值为undefined
,而const
必须在初始化的时候赋值。而创建到初始化之间的代码片段就形成了暂时性死区let u; console.log(u); // undefined
1
2
3const c // Missing initializer in const declaration
1
2
# 函数提升
函数声明会提升, 函数表达式不会
/* Function declaration */
foo(); // "bar"
function foo() {
console.log("bar");
}
/* Function expression */
baz(); // TypeError: baz is not a function
var baz = function() {
console.log("bar2");
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15