以下代码抛出ReferenceError“a未定义”。
{
let a = 'a1';
{
console.log(a);
let a = 'a2';
}
}
和下一个一样。
{
const a = 'a1';
{
console.log(a);
const a = 'a2';
}
}
如果你改为使用var声明,它就像我期望的那样工作。 (没有抛出错误错误并记录'a1'。)
当我尝试分析以下代码时,我更难理解。
{
let a = 'a1';
{
console.log(a);
var a = 'a2';
}
}
抛出一个SyntaxError,“标识符'a'已经被声明了。”
Naïvely我希望一个标识符在一个let或const声明之前被遮蔽,比如在Clojure中let的行为或者在Racket中让*。如described clearly on MDN,这不是它的工作原理。
但为什么以这种方式工作?为什么Racket既有let又有let *形式?
答案 0 :(得分:1)
这是因为将内部let
或const
提升到了区块的顶部(MDN),并创建了时间死区。< / p>
在ECMAScript 2015中,让我们将变量提升到顶部 块。但是,在之前引用块中的变量 变量声明导致ReferenceError。变量在a中 从块的开始直到声明的“时间死区” 处理完毕。
这背后的原因很简单 - 无声失败vs投掷错误。
在此示例中,由于undefined
提升,类似设置将结果显示为var
。这是一个无声的错误,可能很难调试。
{
var a = 'a1';
(function() {
console.log(a);
var a = 'a2';
})();
}
如果您使用let
或const
,则会引发错误:
{
let a = 'a1';
(function() {
console.log(a);
let a = 'a2';
})();
}
您可以在文章TEMPORAL DEAD ZONE (TDZ) DEMYSTIFIED中找到有关时间死区的更多信息。