【问题标题】:When invoking a closure in JavaScript, is a new execution context created when entering the closure code?在 JavaScript 中调用闭包时,输入闭包代码时是否会创建新的执行上下文?
【发布时间】:2013-02-14 20:42:07
【问题描述】:

注意下面的闭包示例:

<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 时会发生什么,但由于这是对函数/闭包的引用,我不确定它是否必须再次经历整个执行上下文创建/绑定阶段。

【问题讨论】:

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


    【解决方案1】:

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

    dummy()Function Call (11.2.3)

    参见步骤#8 “返回调用func内部方法[[Call]]的结果,提供thisValue作为this值,提供list argList作为参数值。” p>

    所以dummy.[[Call]] 被调用。转到13.2.1 ([[Call]])。

    让 funcCtx 成为使用 F 的 [[FormalParameters]] 内部属性的值、传递的参数 List args 和 10.4.3 中所述的 this 值为函数代码建立新执行上下文的结果。

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

    现在 dummy 的功能代码已执行,NewDeclarativeEnvironment 按照 10.4.3 中的步骤 #5 创建并传递 dummy.[[Scope]]

    dummy 只是对bar 的引用,所以dummy.[[Scope]]bar.[[Scope]]。而bar.[[Scope]] 是在foo 执行时定义的(前一行),自然会为其中的每个函数声明创建函数(包括bar)。

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

    x在var的VE中找到,y在bar的VE中找到,alert成功接收3作为参数:)

    但要回答您最初的问题,是的“输入功能代码”发生在

    (function(){ ... })();
    

    如果是

    f();
    

    因为它们本质上都是调用函数的 [[Call]]。只是第一个是CallExpression,由FunctionExpressionArguments 组成,而第二个是CallExpression,由IdentifierArguments 组成。

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

    【讨论】:

      【解决方案2】:

      我认为作用域链就是你在这里看到的东西:

      来自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');}
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-17
        • 2020-12-17
        • 1970-01-01
        相关资源
        最近更新 更多