'let'是否覆盖全局声明并抛出ReferenceError?

时间:2017-01-03 19:44:29

标签: javascript scope ecmascript-6 global 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 :初始化之前无法访问词法声明x(Firefox)

我理解let不允许x提升,但由于它先前被引用(暗示来自全局范围的自动声明),在这种情况下不应该重新声明吗?

  

SyntaxError :标识符x已被声明

因此抛出上述错误?

我也明白,在严格模式中,第一个代码段会抛出 ReferenceError ,所以这是否意味着let强制执行严格模式的特定规则(所有变量都需要在全局范围内声明?

3 个答案:

答案 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将进入严格模式。