JavaScript变量提升

ES 5 以及之前的版本只有 全局作用域函数作用域 两种作用域,在 ES 6 标准中引入了块级作用域这个概念,随之新增了 letconst 两种变量声明方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
x = "global"; // 挂载到全局作用域中

// 函数作用域
(function() {
console.log(x); // 输出 undefined
var x = 'local';
}());

// 块级作用域
{
console.log(x); // 未声明的变量,运行出错
let/const x = 'local';
}

// 闭包
(function() {
console.log(x); // 输出 'global'
})

以上的函数作用域实际过程如下:

1
2
3
4
5
(function() {
var x; // 由变量提升而被声明
console.log(x);
x = 'local'; // 赋值
}())

块级作用域的过程:

1
2
3
4
5
6
{
// 由于变量提升,创建 x,但是 x 未被进行词法绑定,处于暂时死区(temporal dead zone)
console.log(x);
let x; // 此时 x 从暂时死区中离开,已经可以访问
x = 'local'; // 赋值
}

巧妙玩弄(?) 暂时死区:

1
2
3
4
5
let x = x;  // Uncaught ReferenceError: x is not defined

let x = 1; // Uncaught SyntaxError: Identifier 'x' has already been declared

console.log(x); // Uncaught ReferenceError: x is not defined

x 被困在暂时死区中,此后该作用域中 x 无法使用。

函数提升

在红宝书上看到了这个概念,区别函数提升与变量提升:

1
2
3
4
alert(sum(10,10)); // TypeError: sum is not a function
var sum = function(num1, num2) {
return num1 + num2;
};

以上代码会报错,因为虽然 sum 被提升了,但是初始化在后面。

1
2
3
4
alert(sum(10,10));
function sum(num1, num2) {
return num1 + num2;
}

相应的,直接声明函数的形式,因为函数提升直接初始化,所以代码正确运行。

参考

我用了两个月的时间才理解 let

Are variables declared with let or const not hoisted in ES6?

ES6 中 let 暂时性死区详解