ReferenceError: can't access lexical declaration`X' before initialization

ReferenceError: can't access lexical declaration`X' before initialization

谁能给我解释一下在尝试访问 variable before the let declaration: "let X"chrome and firefox 中出现的奇怪错误消息。如果我们这样写:

console.log(X);
let X;

/*
In firefox it reports an error like:

ReferenceError: can't access lexical declaration 'X' before initialization


In chrome it reports and error like:

Uncaught ReferenceError: Cannot access 'X' before initialization

*/

为什么它 returns 像你在上面的代码中看到的错误消息而没有给出像下面的错误消息:

console.log(X);
/* the error message i was expecting:

firefox: ReferenceError: X is not defined

chrome: ReferenceError: X is not defined


*/

这是否也意味着 let 变量 hoist 因为错误消息显示 let variables 的属性被提升意味着 javaScript 引擎知道我们何时尝试访问let variable 在声明之前

console.log(X);
let X;
ReferenceError: can't access lexical declaration 'X' before initialization

如果您在 ECMAScript specification 中发现任何与此行为相关的内容,请告诉我

是的,它们 "hoist" 但作为不可访问的东西,在读取或写入时总是会抛出错误。它被称为 "temporal dead zone".

进一步阅读:https://medium.com/nmc-techblog/advanced-javascript-es6-temporal-dead-zone-default-parameters-and-let-vs-var-deep-dive-ca588fcde21b

Conceptually, for example, a strict definition of hoisting suggests that variable and function declarations are physically moved to the top of your code, but this is not in fact what happens. Instead, the variable and function declarations are put into memory during the compile phase, but stay exactly where you typed them in your code. [Hositing]

[...]

For most of the ES6 features (let, const, default parameters, etc), The Creation Phase work quite differently. It still goes through the code and allocates space for variables, but the initializer set the variables with a special mode called TDZ (Temporal Dead Zone), which means the variables exist but you can’t access them until you assign some value.

所以你可以这样想象:

let X = TDZ;
console.log(X); // error
X = undefined; // in your code: let X;

...与正常托管行为相比:

var X = undefined;
console.log(X); // undefined
X = whatever; // in your code: var X = whatever;

当然这不是 100% 正确,因为你也不能在 let 之前写 X = 123,并且没有有效的 JS 可以描述 "unwritable variable"。但我想你明白了。


ECMAScript 2021 Language Specification this is described in 13.3.1 as follows (it seems it doesn't use the term "TDZ" there, although I have heard this name used many timed before, it's also used in MDN):

13.3.1 Let and Const Declarations

NOTE

let and const declarations define variables that are scoped to the running execution context's LexicalEnvironment. The variables are created when their containing Environment Record is instantiated but may not be accessed in any way until the variable's LexicalBinding is evaluated. A variable defined by a LexicalBinding with an Initializer is assigned the value of its Initializer's AssignmentExpression when the LexicalBinding is evaluated, not when the variable is created. If a LexicalBinding in a let declaration does not have an Initializer the variable is assigned the value undefined when the LexicalBinding is evaluated.

这意味着在您的块的开头,环境记录被实例化 - 变量 "exists" 但在 TDZ 中。如此处所述,无法访问它,因此出现错误。一旦 let 行被执行,它的 LexicalBinding 被评估并且变量从 TDZ 出来并且现在可以访问。由于您没有指定初始值设定项,它的值现在是 undefined.