是否为每个嵌套函数创建了一个单独的闭包实例?

时间:2011-05-26 22:37:37

标签: javascript

道歉,如果我的术语稍微偏离......当一个函数包装另一个函数并创建一个闭包时,每次调用外部函数时是否创建了一个闭包的新实例(“内存空间”?)?

从我的代码中我相信答案是肯定的:

(function(){
  var ob = {}, names=['one', 'two'], i=0;

  var outer = function(val){

    ob[names[i++]] = function(){
      return val;
    };

  };

  outer(3);
  outer(999);

  console.log(ob.one());
  console.log(ob.two());
})();

鉴于结果是

3
999

而不是

999
999

似乎ob.one指向ob.two的另一个闭包实例 - 每个val都有自己的值。

这比我的术语更令人困惑吗?

2 个答案:

答案 0 :(得分:3)

  

是否为每个嵌套函数创建了一个单独的闭包实例?

是的,这是一个理想的功能

更令人向往的功能是块级范围,javascript没有。实际上,有必要滥用嵌套函数以便在javascript中执行嵌套for - 循环,否则变量绑定将在您的背后变异(例如,如果您将其交给回调,您自己演示;想象一下你所定义的函数,例如,针对不同元素的onClick处理程序;你想要绑定是不同的。)

当然,如果你不喜欢这个功能,你总是可以使用你在外部范围内定义的变量,比如你也可以。 =)

答案 1 :(得分:0)

如果ob被调用inner会更好,但无论如何......

  

...每次调用外部函数时都会创建一个闭包的新实例(“内存空间”?)?

是和否。分配给外部的函数具有对外部匿名函数的激活/变量对象的闭包。调用外部时,该对象将放置在其作用域链上,并用于标识符解析。这是每次都是相同的对象(ECMA-262没有说明如何做到这一点,但是对于所有意图和目的而言,它是同一个对象)。

分配给ob[names[i++]]的函数对调用外部并分配函数时创建的激活/变量对象的实例有一个闭包。因此,每次调用外部时,都会创建一个新的激活/变量对象,并且每个 ob [..] 函数都有一个对不同外部激活/变量对象但具有相同的匿名函数激活/变量对象。

我希望这是有道理的。

  

鉴于结果是

     

3 999

     

而不是

     

999 999

     

似乎ob.one指向a   ob.two的不同闭包实例    - 每个都有自己的val值。

两个函数在其作用域链上具有相同的匿名函数激活/变量对象,因此“共享”对 obj 名称 i <的闭包/ em>的。但每个作为其范围链上的外部激活/变量对象的唯一实例,因此 val 将解析为相同的属性名称,但在不同的对象上(即它们不会共享相同的 val 属性)。

可能下面的范围链图是有意义的:

ob.one -> outerA -> anonymous fn -> global
ob.two -> outerB -> anonymous fn -> global

所以 ob.one ob.two 在其作用域链上有一个外部实例,但它们是不同的实例。它们在作用域链上具有相同的匿名函数和全局对象。