【问题标题】:Why hoist variables when there is TDZ有 TDZ 时为什么要提升变量
【发布时间】:2026-01-06 07:10:02
【问题描述】:

ES6 标准提出了 Temporal Dead Zones,使得在评估词法绑定之前无法以任何方式引用变量。那么在词法环境初始化时创建变量意味着什么

  1. 程序员?
  2. 编译器?

使用var 声明的变量声明在以前对程序员来说可能意味着什么,但现在有了 TDZ,javascript 是否开始像 java 一样为此目的?除了 javascript 解释器的工作方式之外,还有什么原因让我们首先提升(因此是 TDZ)?

如果由于执行顺序而在代码中稍后遇到词法绑定,即使代码出现在词法上,会发生什么情况?

let abc = f();
let b;
f(){ return b;}

像 java 这样的传统编程语言何时创建变量?什么时候遇到变量声明?或者什么时候初始化词法范围?

【问题讨论】:

  • 可能是因为很多问题一般google都能解决
  • 不是真的,我尝试了其中的大多数,比如 java 之类的语言何时创建变量,却空手而归。大多数资源 TBZ 都有很好的解释,但他们没有解释为什么我们首先想要它,因为现在是否提升变量并不重要(仅块范围的元素)
  • @sasidhar,“创建”变量有多个不同的步骤。您是在谈论它们何时被识别为变量?您是在谈论他们的内存地址空间何时被填充?许多语言以截然不同的方式“创建”变量,您必须查看每种语言在语言上下文中的处理方式。
  • 我认为 es6 变化不大,只是在使用 let 时将其澄清并将其应用于块而不是函数。看看咖啡脚本的 js 输出如何在顶部列出所有 var,并想象 js 函数在内部做同样的事情。 var 是“可见但为空的”,直到您为其赋值。
  • @dandavis 我不同意,es6 有重大影响,TDZ 现在使typeof 验证成为不可能。 TDZ 是强制更改,如果不是这种情况,那么它将是功能范围更改为块范围的简单情况。

标签: javascript lexical-scope


【解决方案1】:

我有一种感觉,TDZ 的创建与 var 的一个非常微不足道的步骤有关,而如果他们采用看似更合乎逻辑的方法,甚至不存在标识符,引擎就会有进行更深入的变革。至于您的问题的第二部分,即其他语言何时“创建”变量,还有许多其他重要因素需要考虑,您似乎忽略了,例如语言是解释还是编译,以及有多个“创建”变量的不同步骤。它在许多不同的情况下表现不同,并且没有单一的答案。事实上,这就是为什么有许多不同的语言的重要原因之一。

至于您的编码问题,这取决于您何时调用 f 函数,因为函数声明是在 javascript 中提升的。如果您在声明 b 之前调用它,那么您在 TDZ 中并且无法引用 b。它的行为非常相似,就像您只是将 return b 放在调用此函数的任何位置一样。

老实说,似乎对 javascript 和一般计算机语言存在一些潜在的误解。 Javascript 不像 java 那样“行为”,实际上新的 let 关键字具有非常细微的行为,例如与 java 中的类型/变量声明相比,可以是块作用域。我建议不要试图用其他语言来考虑 ES6 的变化; javascript 与许多其他语言不同,如果你理解这些概念以及你应该如何使用 javascript 编程,将会非常困难。


编辑:

至于为什么会有变量和函数声明的提升,那就是easily googlable.

【讨论】:

    【解决方案2】:

    那么在词法环境的时候创建变量是怎么回事 初始化对程序员意味着什么?

    不多。程序员只打算使用声明和初始化的变量。

    该变量在整个范围内都可用(从一开始)仅意味着更容易发现错误,因为在初始化之前使用该变量会失败(有一个例外),而不是默默地解决到外部-范围(全局?)变量。这也意味着标识符,无论它在作用域中的什么位置使用,总是引用局部变量——这正是我们对作用域的期望。

    那么在词法环境的时候创建变量是怎么回事 初始化对编译器意味着什么?

    词法环境在执行期间不会改变其结构。已知范围内标识符的静态解析使得编译成为可能,并且执行速度更快。

    作为一个反例,考虑一下这件事:

    var x = "global";
    var code = "var x = 'local';";
    (function() {
         "use sloppy";
         function test() {
             console.log(x); // what do you think does `x` refer to?
         }                   // It's hard to understand as a developer,
                             // now imagine being a compiler that tries to optimise `test`.
         test();
         eval(code);
         test();
    }());
    

    当稍后在代码中遇到词法绑定时会发生什么 由于执行顺序,即使代码出现在它之前?

    b 在初始化之前用于调用f()。访问它会引发 TDZ 异常。
    You can try it online

    【讨论】:

      最近更新 更多