34

→ 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。我认为这是由于 functionresult2()和 functionresult()等于 function f1()

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

4

7 回答 7

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它们所属的闭包中对局部变量进行操作。

于 2013-10-30T09:11:51.653 回答
28

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

在此处输入图像描述

于 2013-10-30T18:47:25.110 回答
13

每次打电话给f1()你:

  • 创建一个名为的新(局部)变量n,其值为999
  • 创建一个分配给全局 nAdd的新无名函数,该函数修改它n(并覆盖分配给的任何先前函数nAdd
  • 创建一个您返回的新函数,该函数会提醒该函数的值n

你打电话f1()两次,所以你做了两次。第二次调用它时,您将使用修改secondnAdd的新函数覆盖。 n

这给你留下了:

  • result()这会提醒第一个 n
  • result2()这会提醒第二个 n
  • nAdd()增加第二个 n

result()在最后一行 alerts999因为它提醒第一个的值 n从未增加)。

于 2013-10-30T09:12:15.670 回答
4

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

于 2013-10-30T09:11:37.097 回答
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
于 2013-10-30T09:27:18.257 回答
0

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

变量 n=999; 函数 f1(){
nAdd=函数(){n+=1;};
函数 f2(){
console.log(n);
}
返回 f2;
}
变种结果 = f1();
var 结果2 = f1();
结果(); // 999
nAdd();
结果2();//1000
结果2();//1000
结果();//1000

于 2013-10-30T11:04:59.677 回答
0

是这样的:</p>

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
于 2013-11-06T01:32:54.100 回答