JavaScriptclosures困惑
→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?
每次调用f1()
,都会使用自己的本地n
variables创build一个新的闭包。
然而, nAdd
variables是全局variables,因此每次调用f1()
时都会被覆盖 – 这意味着调用nAdd()
只会添加到最后一个闭包中的n
variables中。
更新:如果你想能够独立地增加每个闭包中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()
返回一个包含两个未声明为全局variables的方法的对象,并且这两个方法都是在它们所属的闭包的本地n
variables上进行操作的。
已经有了很好的答案,但是我猜想一张图片会有助于理解。
每次你打电话给f1()
你:
- 创build一个名为
n
的新(本地)variables,值为999
- 创build一个新的分配给全局
nAdd
无名函数,修改n
(并覆盖任何先前分配给nAdd
函数) - 创build一个新的函数,返回哪个警报
n
的值
你调用f1()
两次,所以你做了两次。 第二次调用它时,你nAdd
用一个修改第二个 n
的新函数覆盖nAdd
。
这给你留下了:
-
result()
提醒第一个n
-
result2()
提醒第二个n
-
nAdd()
增加第二个n
最后一行的result()
提示999
因为它会提醒前 n
值(从未递增)。
result
和result2
包含f1
不同调用的结果,因此包含局部variablesn
不同实例。 函数的每个调用对于该函数的局部variables可能具有不同的值。 甚至在没有closures时也适用。
nAdd=function(){n+=1;};
行创build一个全局函数,它是f1()
一个闭包。 闭包也可以访问创build它的函数的范围。 所以每次调用f1()
,都会创build一个新的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
结果和结果2创build两个不同的nclosures。 如果通过在f1()函数之外声明它来使得全局variables为na,那么您将得到您所期望的结果,因为在这种情况下,您将始终访问全局variablesn:
var n = 999; 函数f1(){
n添加=函数(){N + = 1;};
函数f2(){
的console.log(N);
}
返回f2;
}
var result = f1();
var result2 = f1();
结果(); // 999
n添加();
RESULT2(); // 1000
RESULT2(); // 1000
结果(); // 1000
它是这样的:
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