javascript中的范围和关闭奇怪

时间:2016-11-30 12:48:58

标签: javascript function ecmascript-6 closures hoisting

这是昨天在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
}

有人可以向我解释这件事是如何运作的吗?对于记录,它的仅在非严格模式下工作

谢谢。

1 个答案:

答案 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提升,pf都在代码段的顶部有效地声明了初始值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试图取得平衡)。