# let, const, var
# 变量提升
当你使用var
去定义变量时, 在编译 JS 时变量会全部提升到当前作用域的顶部.
同时在全局作用域定义的变量都会成为window
的属性
# 作用域
# ES6 之前
只有全局作用域和函数作用域
# ES6 之后
全局作用域 和 函数作用域 和 块级作用域
# 创建块级作用域
ES6 后新增了块级作用域, 用{}
括住:
{ let x = 1; } console.log(x); // Uncaught ReferenceError: x is not defined
Copied!
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;
Copied!
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;
Copied!
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);
Copied!
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); }
Copied!
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
Copied!
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
Copied!1
2
3const c // Missing initializer in const declaration
Copied!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"); };
Copied!
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