9.4 暂时性死区(temporal dead zone)
let
或 const
声明的变量拥有暂时性死区(TDZ):当进入它的作用域,它不能被访问(获取或设置)直到执行到达声明。
首先看看不具有暂时性死区的 var
:
- 当进入
var
变量的作用域(包围它的函数),立即为它创建(绑定)存储空间。变量会立即被初始化并赋值为undefined
。 - 当执行到变量声明的时候,如果变量定义了值则会被赋值。
通过 let
声明的变量拥有暂时性死区,生命周期如下:
- 当进入
let
变量的作用域(包围它的语法块),立即为它创建(绑定)存储空间。此时变量仍是未初始化的。 - 获取或设置未初始化的变量将抛出异常
ReferenceError
。 - 当执行到变量声明的时候,如果变量定义了值则会被赋值。如果没有定义值,则赋值为
undefined
。
const
工作方式与 let
类似,但是定义的时候必须赋值并且不能改变。
在 TDZ 内部,如果获取或设置变量将抛出异常:
if (true) { // enter new scope, TDZ starts
// Uninitialized binding for `tmp` is created
tmp = 'abc'; // ReferenceError
console.log(tmp); // ReferenceError
let tmp; // TDZ ends, `tmp` is initialized with `undefined`
console.log(tmp); // undefined
tmp = 123;
console.log(tmp); // 123
}
下面的示例将演示死区(dead zone)是真正短暂的(基于时间)和不受空间条件限制(基于位置)
if (true) { // enter new scope, TDZ starts
const func = function () {
console.log(myVar); // OK!
};
// Here we are within the TDZ and
// accessing `myVar` would cause a `ReferenceError`
let myVar = 3; // TDZ ends
func(); // called outside TDZ
}
9.4.1 typeof
与暂时性死区
变量在暂时性死区无法被访问,所以无法对它使用 typeof
:
if (true) {
console.log(typeof tmp); // ReferenceError
let tmp;
}
我不认为这对大多数程序员来说是个问题:用这种方式检查变量是否存在的主要存在于库中 (特别是 polyfills)。如果你需要检查一个变量是否存在,你可以通过其他的方式(例如通过 window
)。最后,从长远来看模块会减少这种类型的需求。