Scoping and closure oddities in javascript
这是昨天在TC39上提出的。 你可以在这里找到要点:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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 } |
有人可以向我解释这件事是如何运作的吗? 对于记录,它仅在非严格模式下工作。
谢谢。
我不会声称理解所有细微之处,但关键是关于附件B§B.3.3.1的几乎奇怪的扭曲。
该代码实际上是这样的,其中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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 } |
当然,由于
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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中的关键位是它将内部
3. When the FunctionDeclaration f is evaluated, perform the following steps in place of the FunctionDeclaration Evaluation algorithm provided in 14.1.21:
a. Let fenv be the running execution context's VariableEnvironment.
b. Let fenvRec be fenv's EnvironmentRecord.
c. Let benv be the running execution context's LexicalEnvironment.
d. Let benvRec be benv's EnvironmentRecord.
e. Let fobj be ! benvRec.GetBindingValue(F, false).
f. Perform ! fenvRec.SetMutableBinding(F, fobj, false).
g. Return NormalCompletion(empty).
回想一下,变量环境是功能范围的,但词汇环境更受限制(到块)。
在尝试将函数声明标准化为{invalid |的地方时未指定}(选择你的术语),TC39有一个非常危险的导航路径,试图标准化行为,同时不破坏可能依赖于过去的实现特定行为的现有代码(这是相互排斥的,但TC39正试图冲帐)。