这是昨天在TC39上发布的。你可以找到要点here:
var p = () => console.log(f);
{
p(); // undefined
console.log(f); // function f(){}
f = 1;
p(); // undefined
console.log(f); // 1
function f(){}
p(); // 1
console.log(f); // 1
f = 2;
p(); // 1
console.log(f); // 2
}
有人可以向我解释这件事是如何运作的吗?对于记录,它的仅在非严格模式下工作。
谢谢。
答案 0 :(得分:2)
我不会声称理解所有细微之处,但关键是关于附件B §B.3.3.1几乎奇怪的扭曲。
该代码实际上是这样的,其中f1
是特定于块的词法环境的f
的第二个副本(因此下面是let
):
var p = () => console.log(f);
{
let f1 = function f(){};; // Note hoisting
p(); // undefined
console.log(f1); // function f(){}
f1 = 1;
p(); // undefined
console.log(f1); // 1
var f = f1; // !!!
p(); // 1
console.log(f1); // 1
f1 = 2;
p(); // 1
console.log(f1); // 2
}
当然,感谢var
提升,p
和f
都在代码段的顶部有效地声明了初始值undefined
:
var f = undefined;
var p = undefined;
p = () => console.log(f);
{
let f1 = function f(){};; // Note hoisting
p(); // undefined
console.log(f1); // function f(){}
f1 = 1;
p(); // undefined
console.log(f1); // 1
f = f1; // !!!
p(); // 1
console.log(f1); // 1
f1 = 2;
p(); // 1
console.log(f1); // 2
}
B.3.3.1中的关键位是它将内部f
(上面我称之为f1
)的值传递给外部的值(在下面, F 是字符串"f"
,即声明的函数的名称:
3。在评估FunctionDeclaration f 时,执行以下步骤代替14.1.21中提供的FunctionDeclaration Evaluation算法:
一个。让 fenv 成为正在运行的执行上下文的VariableEnvironment。
湾让 fenvRec 成为 fenv 的EnvironmentRecord。
℃。让 benv 成为正在运行的执行上下文的LexicalEnvironment。
d。让 benvRec 成为benv的EnvironmentRecord。
即让 fobj 成为! benvRec.GetBindingValue( F ,false)。
F。表演! fenvRec.SetMutableBinding( F , fobj ,false)。
克。返回NormalCompletion(空)。
回想一下变量环境是功能范围的,但词汇环境受限制更多(到块)。
在尝试将函数声明标准化为{invalid |未指定} (选择您的术语),TC39有一个非常危险的导航路径,尝试标准化行为,同时不破坏可能依赖于特定于实现的行为的现有代码过去(相互排斥,但TC39试图取得平衡)。