'let' 是否覆盖全局声明并抛出 ReferenceError?
Does 'let' override a global declaration and throws a ReferenceError?
我正在查看 var
和 let
文档示例之间的差异,并测试当调用未声明的变量时,全局范围会自动为其提供声明(这就是为什么以下内容片段不会在任何变量中引发错误):
x = 3;
console.log(x);
(function() {
y=x+39;
})()
console.log(y);
然而,当一个变量在同一全局范围内赋值后用let
声明时:
x=3;
let x = 42;
console.log(x);
抛出以下错误之一:
ReferenceError: x
is not defined (Chromium)
ReferenceError: can't access lexical declaration x
before initialization (Firefox)
我知道 let
不允许 x
提升,但由于它之前被引用(暗示从全局范围自动声明)在这种情况下不应该重新声明发生了什么?
SyntaxError: Identifierx
has already been declared
因此抛出了上面的错误?
我也明白在严格模式中第一个片段会抛出一个ReferenceError,所以这是否意味着let
在全局范围内强制执行此严格模式的特定规则(所有变量都需要声明)?
您是否看过 MDN 上的 let
文档?他们用 let 描述了一个 时间死区和错误。
ES6 确实将 let
变量提升到其作用域的顶部。与 var
变量不同,当使用 let
时,您不能在变量声明之前访问它。这样做失败并出现 ReferenceError
(a.k.a。 让我们暂时死区 )。
正如 Konstantin A. Magg 所解释的,那是因为 let
变量被提升并尝试在初始化抛出(时间死区)之前引用它们。
如果你不想这样,你可以将代码拆分成不同的脚本:
<script>
x = 3;
console.log(x); // 3
</script>
<script>
let x = 42;
console.log(x); // 42
</script>
注意 x = 3
将在严格模式下抛出。
你说得对,这是一种奇怪的行为。它给出这些错误的原因是因为它认为您正在尝试将值 3
分配给您的 let
变量而不是全局值。正如其他人提到的,这会导致提升的时间死区问题。
The variables are created when their containing Lexical Environment is
instantiated but may not be accessed in any way until the variable’s
LexicalBinding is evaluated
- Source (ECMAScript 8th edition)
此代码显示放置代码导致 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
我正在查看 var
和 let
文档示例之间的差异,并测试当调用未声明的变量时,全局范围会自动为其提供声明(这就是为什么以下内容片段不会在任何变量中引发错误):
x = 3;
console.log(x);
(function() {
y=x+39;
})()
console.log(y);
然而,当一个变量在同一全局范围内赋值后用let
声明时:
x=3;
let x = 42;
console.log(x);
抛出以下错误之一:
ReferenceError:
x
is not defined (Chromium)ReferenceError: can't access lexical declaration
x
before initialization (Firefox)
我知道 let
不允许 x
提升,但由于它之前被引用(暗示从全局范围自动声明)在这种情况下不应该重新声明发生了什么?
SyntaxError: Identifier
x
has already been declared
因此抛出了上面的错误?
我也明白在严格模式中第一个片段会抛出一个ReferenceError,所以这是否意味着let
在全局范围内强制执行此严格模式的特定规则(所有变量都需要声明)?
您是否看过 MDN 上的 let
文档?他们用 let 描述了一个 时间死区和错误。
ES6 确实将 let
变量提升到其作用域的顶部。与 var
变量不同,当使用 let
时,您不能在变量声明之前访问它。这样做失败并出现 ReferenceError
(a.k.a。 让我们暂时死区 )。
正如 Konstantin A. Magg 所解释的,那是因为 let
变量被提升并尝试在初始化抛出(时间死区)之前引用它们。
如果你不想这样,你可以将代码拆分成不同的脚本:
<script>
x = 3;
console.log(x); // 3
</script>
<script>
let x = 42;
console.log(x); // 42
</script>
注意 x = 3
将在严格模式下抛出。
你说得对,这是一种奇怪的行为。它给出这些错误的原因是因为它认为您正在尝试将值 3
分配给您的 let
变量而不是全局值。正如其他人提到的,这会导致提升的时间死区问题。
The variables are created when their containing Lexical Environment is instantiated but may not be accessed in any way until the variable’s LexicalBinding is evaluated
- Source (ECMAScript 8th edition)
此代码显示放置代码导致 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