2013-10-30 81 views
33

→ jsFiddle一个JavaScript封闭混乱

function f1(){ 
    var n=999; 

    nAdd=function(){n+=1;}; 

    function f2(){ 
     alert(n); 
    } 
    return f2; 
} 

var result = f1(); 
var result2 = f1(); 

result(); // 999 
nAdd(); 
result2(); // 1000 
result2(); // 1000 
result(); // 999 

我努力学习JavaScript关闭,但上述只是让我困惑的代码。 当第一次调用result()时,它是999.对我来说没关系。

nAdd()之后被调用,result2()节目1000我认为这是由于功能result2()和功能result()是平等的运作f1()

但为什么最后的result()显示999而不是1000?

回答

36

每次调用f1()时,都会创建一个具有自己的本地变量n的新闭包。

然而,nAdd变量是全球性的,因此会被覆盖每个f1()被调用的时候 - 这意味着呼吁nAdd()将只添加到n变量在最后关闭。

UPDATE:如果你希望能够增加在每个封闭的n值独立,你可以做这样的事情:

function f1(){ 
    var n=999; 
    return { 
     incrementN : function(){n+=1;}, 
     getN : function f2(){console.log(n);} 
    } 
}  
var result = f1(); 
var result2 = f1(); 
result.getN(); // 999 
result.incrementN(); 
result2.getN();//999 
result2.incrementN(); 
result2.getN();//1000 
result.getN();//1000 

也就是说,有f1()返回一个包含两个方法是不是对象声明为全局变量,并且它们都在它们所属的闭包中的本地变量上运行。

4

resultresult2包含的f1不同调用的结果,并且因此含有局部变量n的不同实例。函数的每个调用对于该函数的局部变量可能具有不同的值。甚至在不涉及关闭时也适用。

+1

+1。每次输入执行上下文时,都会创建一组新的变量。 – RobG

13

每次调用f1()你时间:

  • 创建的999
  • 的值称为n一个新的(本地)变量创建分配给全球nAdd的修改时n一个新的匿名函数(并覆盖以前分配给nAdd的所有功能)
  • 创建一个新函数,返回哪个警报的值

您可以拨打f1()两次,这样你就可以做到两次。第二次调用它时,用覆盖nAdd的新函数修改第二个n

这留给你:

  • result()这提醒第一n
  • result2()这提醒第二n
  • nAdd()其递增第二n

result()在最后一行提醒999,因为它会提醒的第一n值(它从未递增)。

+2

变量* nAdd *创建一次:第一次* f1 *在赋值语句被评估的位置被调用。之后,它只是每次调用* f1 *时改变的值。也许这只是说出你所说的话的另一种方式。 : -/ – RobG

1

nAdd=function(){n+=1;};行创建一个全局函数,它是f1()中的一个闭包。闭包也可以访问创建它的函数范围中的所有变量。因此,每次您拨打f1()时,都会创建一个新的nAdd()函数,其中n的值与f1()的调用值var n相关。

在你的代码中;

var result = f1(); 
var result2 = f1(); 
result(); // 999 
nAdd();   // Created by "var result2 = f1();" and has the same 'n' value as function in result2 
result2();//1000 
result2();//1000 
result();//999 
0

结果和result2创建两个不同的关闭与不同的n。如果您呐通过声明它之外的F1()函数的全局变量,那么你会得到你的预期,因为在这种情况下,你总是会访问全局变量n结果:

变种N = 999; function f1(){
nAdd = function(){n + = 1;};
function f2(){
console.log(n);
}
return f2;
}
var result = f1();
var result2 = f1();
result(); // 999
nAdd();
RESULT2(); // 1000
RESULT2(); // 1000
结果(); // 1000

27

目前已经是很好的答案,但我猜的图片将是有益的理解。

enter image description here

+8

+1这是一个非常有创意的方式!最后点击了 – ComFreek

+1

。感谢您的可视化 – Moak

+0

@Moak:不客气。 –

0

它这样:

var nAdd; 
function f1(){ 
    var n=999; 

    nAdd=function(){n+=1;}; 

    function f2(){ 
     alert(n); 
    } 
    return f2; 
} 

var result = f1();//var nAdd=function(){n+=1;} n=result.n=999 

var result2 = f1();//var nAdd=function(){n+=1;} n=result2.n=999 

var result3 = f1();//var nAdd=function(){n+=1;} n=result3.n=999 

nAdd(); 

result(); // 999 

result2(); // 999 

result3(); // 1000 

var result = f1();//var nAdd=function(){n+=1;} n=result.n=999 

var result2 = f1();//var nAdd=function(){n+=1;} n=result2.n=999 

nAdd(); 

var result3 = f1();//var nAdd=function(){n+=1;} n=result3.n=999 


result(); // 999 

result2(); // 1000 

result3(); // 999 

var result = f1();//var nAdd=function(){n+=1;} n=result.n=999 

var result2 = f1();//var nAdd=function(){n+=1;} n=result2.n=999 

nAdd(); 

var result3 = f1();//var nAdd=function(){n+=1;} n=result3.n=999 
nAdd(); 
nAdd(); 
nAdd(); 

result(); // 999 

result2(); // 1000 

result3(); // 1002 
+0

您是否愿意向您的代码解决方案添加解释? –

+0

我猜这个家伙显示3个片段,每个片段都以代码“result3();”结尾。然后可以理解。 – CoolGuy