JavaScript闭包混乱

时间:2013-10-30 09:03:52

标签: javascript closures

→ jsFiddle

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?

7 个答案:

答案 0 :(得分:36)

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

但是,nAdd变量是全局的,因此每次调用f1()时都会被覆盖 - 这意味着调用nAdd()只会添加到n变量中最后关闭。

更新:如果您希望能够独立增加每个闭包中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()返回一个包含两个未声明为全局变量的方法的对象,并且它们都对它们所属的闭包中的本地n变量进行操作。

答案 1 :(得分:27)

已经有了很好的答案,但我想一张照片有助于理解。

enter image description here

答案 2 :(得分:13)

每次致电f1()时:

  • 创建一个名为n的新(本地)变量,其值为999
  • 创建一个新的无名功能,分配给全局 nAdd,修改n(并覆盖分配给nAdd的所有先前功能)
  • 创建一个您返回的新功能,该功能会警告n
  • 的值

你拨打f1()两次,所以你做了两次这样的事情。第二次调用它时,用一个修改第二个 nAdd的新函数覆盖n

这会让你:

  • result()提醒第一个 n
  • result2()提醒第二个 n
  • nAdd()增加 n
最后一行

result()提醒999,因为它会提醒第一个 n(从未增加过)的值。

答案 3 :(得分:4)

resultresult2包含f1的不同调用的结果,因此包含局部变量n的不同实例。函数的每次调用对于该函数的局部变量可以具有不同的值。这甚至适用于没有涉及闭包的情况。

答案 4 :(得分:1)

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

在您的代码中;

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

答案 5 :(得分:0)

结果和result2创建两个不同的闭包。如果你通过在f1()函数之外声明它来使n成为全局变量,那么你将获得你所期望的结果,因为在这种情况下你将始终访问全局变量n:

  

var n = 999;   function f1(){
  n添加=函数(){N + = 1;};
  function f2(){
  的console.log(N);
  }
  返回f2;
  }
  var result = f1();
  var result2 = f1();
  结果(); // 999
  n添加();
  RESULT2(); // 1000
  RESULT2(); // 1000
  结果(); // 1000

答案 6 :(得分: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