【问题标题】:Javascript: how let is hoisted (or not) inside if block? [duplicate]Javascript:如何在 if 块中提升(或不提升)let? [复制]
【发布时间】:2018-05-15 08:07:28
【问题描述】:

在我看来,我已经理解了 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,正如我所料。


我的问题是:

  • let 声明的变量是否在最近的封闭块内被提升?
    • 如果是,为什么第一个块中的代码会导致 Uncaught ReferenceError: a is not defined

【问题讨论】:

    标签: javascript scope ecmascript-6 var let


    【解决方案1】:

    有一个称为Temporal Dead Zone 的句点会影响使用letconst 声明的变量。

    转述this answer

    Temporal Dead Zone — 进入作用域和变量之间的时间段 正在声明中,其中的变量不能被访问。

    所以,如果我们要在第一个代码 sn-p 中标记 Temporal Dead Zone,来自问题:

    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 也提到了这一点(以及其他棘手的案例):

    在 ECMAScript 2015 中,let 绑定不受变量提升的约束,这意味着 let 声明不会移动到当前执行上下文的顶部。在初始化之前引用块中的变量会导致 ReferenceError (与使用 var 声明的变量相反,它只有未定义的值)。从块开始到处理初始化,变量处于“临时死区”中。

    上面的摘录后面跟着这段代码:

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

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

    【讨论】:

    • 对于多种语言共有的行为来说,这是一个非常奇怪的名字?
    • @AbhinavGauniyal 在其他哪些常见语言中,它的行为是相同的,在那里如何称呼它?
    • @Bergi c, c++, java.... 列表还在继续。它们都将显示variable not defined 错误,但在它们中的任何一个中都没有被称为“临时死区”,因为由于没有提升,它非常明显。
    • @AbhinavGauniyal 好吧,所有这些都没有闭包,也不是 temporal 死区,而只是“无用上述声明”。在 JavaScript 中,您可以执行 function example() { alert(x) } let x = 42; example();,其中 xlet 以上的范围内。
    • 对,但是从“让绑定不受变量提升”的影响,我只是认为人们可能会认为 let 没有被提升(即使声明没有被提升,只是绑定)
    猜你喜欢
    • 2016-04-05
    • 2021-01-18
    • 2016-07-01
    • 1970-01-01
    • 2013-02-25
    • 2014-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多