在JavaScript中调用闭包时,是否在输入闭包代码时创建了新的执行上下文?

时间:2013-02-28 15:23:26

标签: javascript function closures ecmascript-5 first-class-functions

请注意下面的闭包示例:

<script>
  function foo() {
    var x = 1;
    function bar() {
      var y = 2;
      alert(x + y);
    }
    return bar;
  }

   var dummy = foo(); // Assign variable binding "dummy" to a reference of the "bar" function.
   dummy(); // When entering the "bar" function code, will it go through the execution context creation phase?
</script>

当调用虚拟变量绑定(将执行“bar”功能代码)时,是否创建了新的执行上下文? ECMAScript规范指定entering function code时会发生什么,但由于这是对函数/闭包的引用,我不确定它是否必须再次完成整个执行上下文创建/绑定阶段。

2 个答案:

答案 0 :(得分:2)

好问题。让我们看看发生了什么:

dummy()Function Call (11.2.3)

参见步骤#8 “返回在func上调用[[Call]]内部方法的结果,提供thisValue作为此值并提供列表argList作为参数值。”

因此调用了dummy.[[Call]]。转到13.2.1[[Call]])。

让funcCtx是使用F的[[FormalParameters]]内部属性的值,传递的参数List args以及10.4.3中描述的该值为函数代码建立新的执行上下文的结果。

所以dummy()确实创建了新的执行上下文,如10.4.3中所述。

现在执行dummy的功能代码,按照10.4.3传递dummy.[[Scope]]

的步骤#5创建NewDeclarativeEnvironment

dummy只是对bar的引用,因此dummy.[[Scope]]bar.[[Scope]]。并且bar.[[Scope]]在执行foo时被定义(前一行),自然地为每个函数声明创建函数(包括bar)。

bar.[[Scope]]本质上是由[global environment][foo VE](变量环境)组成的链。所以在它执行的那一刻它创建了自己的VE并使用foo的VE作为外部。范围链现在由[global environment]->[foo VE]->[bar VE]组成。

在var的VE中找到

x,在条形图的VE中找到y,并且警报成功接收3作为参数:)

但是要回答你原来的问题,是的“输入功能代码”会发生在

的情况下
(function(){ ... })();

以及

的情况
f();

因为它们都基本上调用函数[[Call]]。只有第一个是CallExpression,其中FunctionExpression后跟Arguments,而第二个是CallExpression,其中包含Identifier后跟{Arguments 1}}。

两者仍然解析为一个函数对象,它具有内部[[Call]]方法,这是执行的方法。

答案 1 :(得分:0)

我认为范围链是你在这里看到的东西:

来自http://www.amazon.com/JavaScript-Definitive-Guide-Activate-Guides/dp/0596805527/ref=sr_1_2?ie=UTF8&qid=1362066219&sr=8-2&keywords=javascript(3.10.3)

每次调用一个函数时,它都会创建一个新对象来存储其局部变量,并将该新对象添加到存储的作用域链中,以创建一个新的,更长的链,表示该函数调用的作用域。

对于你的问题是,它将再次通过整个执行上下文,否则如何从bar()返回另一个函数,如

function bar() {
      var y = 2;
      alert(x + y);

return function() {alert('hello');}
    }