【问题标题】:Defined variable in outer scope is not defined in inner scope [duplicate]外部范围内定义的变量未在内部范围内定义[重复]
【发布时间】:2017-01-10 12:59:23
【问题描述】:

以下代码抛出 ReferenceError 'a is not defined'。

{
    let a = 'a1';
    {
        console.log(a);
        let a = 'a2';
    }
}

下一个也是。

{
    const a = 'a1';
    {
        console.log(a);
        const a = 'a2';
    }
}

如果您改为使用 var 声明,它会按我的预期工作。 (没有抛出错误错误并记录了“a1”。)

当我尝试分析以下代码时,我变得更加难以理解。

{
    let a = 'a1';
    {
        console.log(a);
        var a = 'a2';
    }
}

它抛出一个 SyntaxError,“标识符 'a' 已被声明”。

我很天真地希望标识符会被隐藏直到一个 let 或 const 声明之后,就像 Clojure 中的 let 或 Racket 中的 let* 的行为一样。作为described clearly on MDN,这不是它的工作原理。

但是为什么它会这样工作?为什么 Racket 同时具有 let 和 let* 形式?

【问题讨论】:

  • 感谢您的链接,但它没有回答我的问题。我了解它如何 工作,但不了解为什么 选择此模型。是因为性能问题吗?
  • SO 不是问为什么语言具有特定功能或行为的地方。问TC-39,他们不假思索地知道。我可以推测一下。也许提升机制被发现如此重要,以至于它比外部范围变量更受欢迎?
  • @JohanJonasson 为什么选择它?因为 ES6 中的作用域总是基于块/函数体,let 没有引入新的作用域。例如,这确实允许相互递归声明而没有额外的麻烦。此外,当您不确定它所指的是哪个变量时,根本不提供 a 也不太容易出错。
  • 感谢@Bergi,这是一个有趣的答案。如果我理解正确的话,每个 let/const 声明都必须引入一个新的范围,如果它们的行为方式符合我的预期?

标签: javascript scope ecmascript-6


【解决方案1】:

这是由于将内部letconst 提升到块的顶部(MDN),并创建了一个Temporal Dead Zone

在 ECMAScript 2015 中,让我们将变量提升到顶部 堵塞。但是,引用之前块中的变量 变量声明会导致 ReferenceError。变量在一个 从区块开始到声明的“时间死区” 已处理。

这背后的原因很简单——静默失败与抛出错误。

在此示例中,由于 var 提升,类似的设置给出了 undefined 的结果。这是一个静默错误,可能很难调试。

{
    var a = 'a1';
    (function() {
        console.log(a);
        var a = 'a2';
    })();
}

如果您使用letconst,则会引发错误:

{
  let a = 'a1';
  (function() {
    console.log(a);
    let a = 'a2';
  })();
}

您可以在文章TEMPORAL DEAD ZONE (TDZ) DEMYSTIFIED 中找到有关时间死区的更多信息。

【讨论】:

    猜你喜欢
    • 2021-08-18
    • 2019-10-05
    • 1970-01-01
    • 2018-08-09
    • 2015-11-03
    • 1970-01-01
    • 2016-01-13
    • 1970-01-01
    相关资源
    最近更新 更多