ReferenceError:在初始化之前无法访问词法声明`X'
Posted
技术标签:
【中文标题】ReferenceError:在初始化之前无法访问词法声明`X\'【英文标题】:ReferenceError: can't access lexical declaration`X' before initialization [duplicate]ReferenceError:在初始化之前无法访问词法声明`X' 【发布时间】:2020-09-24 19:53:12 【问题描述】:有人能解释一下在尝试访问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
*/
为什么它会返回您在上面的代码中看到的错误消息,而没有给出如下错误消息:
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 中发现与此行为相关的任何内容,请让我知道
【问题讨论】:
为什么不吊起来?它是一个变量,就像一个 var。它只是缩小了范围 那么为什么人们称之为let variables
从不hoist
它们的意思是你不能在定义之前使用它们。如您所见:尝试这样做会引发错误。
然而,一个恼人的副作用当然是,虽然它们以未分配的形式存在,但它们仍然可以隐藏外部范围的变量。因此,在函数的最后一行添加let location
仍然可以破坏整个函数的先前代码,但至少它会以更有意义的方式这样做。如果您将var location
放入函数的最后一行并且您的第一行将完成location = 'http://yahoo.com'
,那么它会静默 破坏代码,但使用let
它会这样做以一种显着的方式。
我意识到实际上已经有更好的答案了:What is the temporal dead zone?
【参考方案1】:
是的,它们“提升”但作为不可访问的东西,在读取或写入时总是会引发错误。它被称为“时间死区”。
延伸阅读:https://medium.com/nmc-techblog/advanced-javascript-es6-temporal-dead-zone-default-parameters-and-let-vs-var-deep-dive-ca588fcde21b
例如,从概念上讲,提升的严格定义表明变量和函数声明在物理上移动到代码的顶部,但实际上并非如此。相反,变量和函数声明在编译阶段被放入内存,但准确地保留在您在代码中键入它们的位置。 [托管]
[...]
对于大多数 ES6 特性(let、const、默认参数等),创建阶段的工作方式完全不同。它仍然会遍历代码并为变量分配空间,但初始化程序使用一种称为 TDZ(Temporal Dead Zone)的特殊模式设置变量,这意味着变量存在但在分配一些值之前您无法访问它们。
所以你可以这样想象:
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 可以描述“不可写变量”。但我想你明白了。
在ECMAScript 2021 Language Specification 13.3.1 中对此进行了如下描述(那里似乎没有使用“TDZ”一词,虽然我以前多次听说过这个名称,但它也在MDN 中使用过):
13.3.1 Let 和 Const 声明
注意
let 和 const 声明定义了范围为正在运行的执行上下文的 LexicalEnvironment 的变量。这些变量是在实例化它们包含的环境记录时创建的,但在评估变量的 LexicalBinding 之前,不得以任何方式访问它们。由具有 Initializer 的 LexicalBinding 定义的变量在评估 LexicalBinding 时分配其 Initializer 的 AssignmentExpression 的值,而不是在创建变量时。如果 let 声明中的 LexicalBinding 没有 Initializer,则在评估 LexicalBinding 时,会为变量分配 undefined 值。
这意味着在您的块开始时,环境记录被实例化 - 变量“存在”但在 TDZ 中。如此处所述,它无法访问,因此出现错误。一旦let
行被执行,它的LexicalBinding 就会被计算并且变量从TDZ 中出来并且现在可以访问了。由于您没有指定初始化程序,因此它的值现在是 undefined
。
【讨论】:
顺便提一下,tc39.es/ecma262 ECMAscript 规范中提到了这个,谢谢你救了我 已将其添加到我的答案中。 非常感谢以上是关于ReferenceError:在初始化之前无法访问词法声明`X'的主要内容,如果未能解决你的问题,请参考以下文章
TypeORM OneToMany 导致“ReferenceError:在初始化之前无法访问'<Entity>'”
未捕获的 ReferenceError:在初始化之前无法访问“GA”
ReferenceError:在初始化React Collapse Component之前无法访问词法声明'useStyles',axios获取数据材料ui useStyles
const commandFolders = readdirSync('./commands'); ReferenceError:在 Object.<anonymous> 初始化之前无法访