我正在浏览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 :初始化之前无法访问词法声明
x
(Firefox)
我理解let
不允许x
提升,但由于它先前被引用(暗示来自全局范围的自动声明),在这种情况下不应该重新声明吗?
SyntaxError :标识符
x
已被声明
因此抛出上述错误?
我也明白,在严格模式中,第一个代码段会抛出 ReferenceError ,所以这是否意味着let
强制执行严格模式的特定规则(所有变量都需要在全局范围内声明?
答案 0 :(得分:2)
您是否查看了MDN处的let
文档?他们用描述了时间死区和错误。
ES6确实将let
变量提升到其范围的顶部。与var
变量不同,使用let
时,在声明变量之前不得访问该变量。这样做会因ReferenceError
(a.k.a。让我们的暂时死区)而失败。
答案 1 :(得分:1)
你是对的,这是一种奇怪的行为。它提供这些错误的原因是因为它认为您尝试将值3
分配给let
变量而不是全局值。正如其他人提到的那样,这会导致暂停死区问题。
变量是在包含词法环境时创建的 实例化但在变量之前可能无法以任何方式访问 评估LexicalBinding
- 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
答案 2 :(得分:0)
正如Konstantin A. Magg所解释的那样,因为let
变量被提升并尝试在初始化之前引用它们(时间死区)。
如果您不想这样,可以将代码拆分为不同的脚本:
<script>
x = 3;
console.log(x); // 3
</script>
<script>
let x = 42;
console.log(x); // 42
</script>
注意x = 3
将进入严格模式。