"let"是否覆盖全局声明并抛出引用错误?



我正在学习varlet之间的差异文档示例,并测试当调用未声明的变量时,全局作用域会自动为其提供声明(这就是为什么以下代码段不会在任何变量中引发错误):

x = 3;
console.log(x);
(function() {
y=x+39;
})()
console.log(y);

但是,当一个变量在同一全局范围内赋值后用let声明时:

x=3;
let x = 42;
console.log(x);

引发以下错误之一:

ReferenceError:未定义x(Chromium)

ReferenceError:在初始化(Firefox)之前无法访问词法声明x

我知道let不允许x提升,但由于它以前被引用过(意味着从全局范围自动声明),在这种情况下不应该重新声明吗?

SyntaxError:标识符x已声明为

因此引发了上述错误?

我还了解到,在严格模式中,第一个代码片段会抛出ReferenceError,那么这是否意味着let将严格模式的这一特定规则(所有变量都需要声明)强制应用于全局范围?

您看过MDN的let文档吗?他们用let描述了时间死区和错误。

ES6确实将let变量提升到其作用域的顶部。与var变量不同,当使用let时,在声明变量之前,您不能访问该变量。使用ReferenceError(也称为,让我们暂时进入死区)无法执行此操作。

你是对的,这是一种奇怪的行为。它给出这些错误的原因是,它认为您试图将值3分配给let变量,而不是全局值。正如其他人所提到的,这导致了吊装的时间死区问题。

当变量包含的词法环境为实例化但可能不会以任何方式访问,直到变量评估LexicalBinding

来源(ECMAScript第8版)

此代码显示放置代码导致TDZ:的位置

// Accessing `x` here before control flow evaluates the `let x` statement
// would throw a ReferenceError due to TDZ.
// console.log(x);
let x = 42;
// From here on, accessing `x` is perfectly fine!
console.log(x);

您可以看到,将let封装在自己的块块中可以修复它:

x=3;
{
let x = 42;
console.log(x); // 42
}

或者,您可以在window对象上显式定义全局:

window.x=3;
let x = 42;
console.log(x);  // 42

正如Konstantin A.Magg所解释的,这是因为let变量被提升,并试图在初始化抛出之前引用它们(暂时死区)。

如果你不想这样,你可以把代码分成不同的脚本:

<script>
x = 3;
console.log(x); // 3
</script>
<script>
let x = 42;
console.log(x); // 42
</script>

注意x = 3将以严格模式抛出。

最新更新