考虑一下:
'use strict';
{
let p = 1;
{
console.log(p);
let p = 2;
}
}
直觉告诉我们它应该记录“1”(因为 var 在重新声明之前必须保留其旧值)。但是,实际结果是 ReferenceError。这是为什么? (将不胜感激基于标准的解释)。
请注意,我已经在外部作用域中声明了 p
,所以它在内部 block 中是已知的。如果您注释掉 p=2
行,一切正常。
作为事后分析,虽然这种行为似乎已记录在案,但它仍然非常违反直觉,请参见。这个 C 代码:
void main() {
int p = 1;
{
printf("%d\n", p); // prints '1'
int p = 2;
}
}
还有一个 JS fuckup 特性需要记下!
根据 MDN :
In ECMAScript 2015, let bindings are not subject to Variable Hoisting, which means that let declarations do not move to the top of the current execution context. Referencing the variable in the block before the initialization results in a ReferenceError (contrary to a variable declared with var, which will just have the undefined value). The variable is in a "temporal dead zone" from the start of the block until the initialization is processed.
问题是你的 let p 语句创建了一个新变量,它的作用域是整个代码块。因此 console.log(p) 中的 p;指的是新创建的变量。
提供了一个与您的情况类似的例子:
function test(){
var foo = 33;
if (true) {
let foo = (foo + 55); // ReferenceError
}
}
test();
Due to lexical scoping, the identifier "foo" inside the expression (foo + 55) evaluates to the if block's foo, and not the overlying variable foo with the value of 33.
In that very line, the if block's "foo" has already been created in the lexical environment, but has not yet reached (and terminated) its initialization (which is part of the statement itself): it's still in the temporal dead zone.