我正在学习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
(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
将以严格模式抛出。