Javascript: let 如何在 if 块内被提升(或不提升)?

Javascript: how let is hoisted (or not) inside if block?

在我看来,我已经理解了 JavaScript 作用域和提升的基本概念。 question+answer 在这方面对我帮助很大。

不过,最近我遇到了一些让我有点吃惊的事情。考虑以下代码:

var a = 1;

if (true) {
  console.log(a);
  let a = 2;
}

console.log(a);

鉴于我所学,我希望它输出 undefined1。虽然结果是 Uncaught ReferenceError: a is not defined.

我的理解是,上面的代码应该等价于(因为 let a = 2; 的声明部分应该被提升到最近的封闭块——在这种情况下是 if):

var a = 1;

if (true) {
  let a;
  console.log(a);
  a = 2;
}

console.log(a);

顺便说一下,这段代码会产生 undefined1,正如我所期望的那样。


我的问题是:

有一个时期叫做Temporal Dead Zone, which affect variables declared with let and const

解释

Temporal Dead Zone — is a period between entering scope and variable being declared, in which variable can not be accessed.

所以,如果我们要在第一个代码片段中标记时间死区,从问题:

var a = 1;

if (true) {
  /* start of the Temporal Dead Zone */
  console.log(a); /* code in the Temporal Dead Zone */
  /* last line of the Temporal Dead Zone */
  let a = 2; /* end of the Temporal Dead Zone */
}

console.log(a);

当然,documentation 也提到了这一点(以及其他棘手的案例):

In ECMAScript 2015, let bindings are not subject to Variable Hoisting, which means that let declarations do not move to the top of the current execution context. Referencing the variable in the block before the initialization results in a ReferenceError (contrary to a variable declared with var, which will just have the undefined value). The variable is in a "temporal dead zone" from the start of the block until the initialization is processed.

上面的摘录后面是这段代码:

function do_something() {
console.log(bar); // undefined
console.log(foo); // ReferenceError
var bar = 1;
let foo = 2;
}

要明确地解决这个问题:如 中所述 - 用 let 声明的变量被提升,但未初始化,在它们最近的封闭块。这连续地导致了可变行为,就好像它们没有被提升一样 =)