我一直在试图弄清楚let
和const
的时间死区/解析是如何工作的。这就是它似乎归结为(基于我在之前的问题[例如this和this]中收到的文档和各种回复,尽管如果出现分歧,这会得到一些答案)。这个摘要是否正确?
在作用域的顶部,JS引擎在相关作用域的顶部创建一个绑定(变量关键字和名称的关联,例如let foo;
),这被认为是提升变量,但是如果您尝试在声明位置之前访问变量,JS会抛出ReferenceError
。
一旦JS引擎向下移动到声明(与“定义”同义),例如let foo;
,引擎就会初始化它(为它分配内存并使其可访问)。声明具有自我约束力。 (这是对我没有意义的部分:绑定导致顶部的提升,但是引擎在达到声明之前不会初始化,声明也具有绑定效果。)如果没有在undefined
的情况下,变量的值设置为let
,如果使用const
,则会抛出SyntaxError
。
此处参考具体说明:
ECMAScript 2019语言规范草案:第13.3.1节,Let and Const Declarations
let和const声明定义作用域的变量 运行执行上下文的LexicalEnvironment。变量是 在实例化包含词法环境时创建但是 在变量的LexicalBinding之前,可能无法以任何方式访问它 评估。由带有初始化程序的LexicalBinding定义的变量 被赋值为Initializer的AssignmentExpression的值 评估LexicalBinding,而不是在创建变量时。如果 let声明中的LexicalBinding没有初始化器 当LexicalBinding为时,变量被赋值undefined 评价。
MDN网络文档:Let
让绑定在包含的(块)范围的顶部创建 声明,通常称为“吊装”。与变量不同 用var声明,它将以undefined值开头,let 在评估定义之前,不会初始化变量。 在初始化之前访问变量会导致a 引发ReferenceError。该变量位于“时间死区” 块的开始直到处理初始化。
答案 0 :(得分:0)
TDZ的理解非常复杂,需要一篇博客文章来阐明其实际效果。 但实质上,过于简化的解释是
let / const声明会提升,但是在初始化之前访问时会抛出错误(而不是像var那样返回undefined)
我们来看这个例子
let x = 'outer scope';
(function() {
console.log(x);
let x = 'inner scope';
}());
由于TDZ语义,上面的代码将抛出一个ReferenceError。
所有这些都来自great article完全关于 TDZ 。 感谢作者。
答案 1 :(得分:0)
也许首先您需要了解TDZ存在的原因:因为它可以防止变量提升的常见惊人行为并修复潜在的错误来源。 E.g:
var foo = 'bar';
(function () {
console.log(foo);
var foo = 'baz';
})();
这是许多(新手)程序员经常出人意料的原因。 It's too late to change the behaviour of var
now,因此ECMAScript小组决定至少通过引入let
和const
来修复行为。究竟是如何在幕后实施的是一个有点没有用的点,重要的是它能够阻止它最有可能成为一个错字/结构性错误:
let foo = 'bar';
(function () {
console.log(foo);
let foo = 'baz';
})();
实际上,Javascript是在两个步骤中执行的:
解析器将在第一步中看到var
/ let
/ const
声明,并将使用保留符号名称等设置范围。那是悬挂。在第二步中,代码将在该设置范围内起作用。显而易见的是,解析器/引擎可以在第一步中自由地执行任何操作,其中一项操作是在内部标记TDZ,这将在运行时引发错误。