var foo = (function(){
var x = 0;
return function(){return x++;};
})()
对于这个问题,我最大的误解是为什么 var x = 0 表达式只运行一次。
var foo = (function(){
var x = 0;
return function(){return x++;};
})()
对于这个问题,我最大的误解是为什么 var x = 0 表达式只运行一次。
你的代码:
var foo = (function(){
var x = 0;
return function(){return x++;};
})()
等同于这段代码:
function f(){
var x = 0;
return function(){return x++;};
}
var foo = f();
很容易看出来,当你像这样分解它时,函数f()
仅被调用一次。它定义了x
,然后返回一个在 f
本地作用域内定义的新函数。这个新函数通常被称为“匿名函数”(意思是它没有名称)或“闭包”。事实上,所有 javascript 中的函数都是“闭包”——无论它们是否具有名称。术语“闭包”只是指该函数保留对其父函数作用域中定义的变量的访问权——即使父函数已经退出。foo
包含从f
返回的新函数(闭包)。您可以随意调用 foo()
——每次调用时,将返回并且后增加x
的值。由于x
存在于闭包的父作用域中,所以其值将在对闭包的多次调用之间保持不变。f()
退出,其他代码就无法再访问 x
了——这基本上意味着x
现在是闭包的“私有数据”。相当神奇,对吧?function(x){return x;}
是一个身份函数,而不是闭包——它不需要词法状态。 - tobyodavieseval
使用调用者的词法作用域...取消1ed。 - tobyodaviesfoo
赋值为自执行函数的结果,该函数如下:x
的变量,并将其初始化为 0
。
返回一个函数,当调用它时,将增加 x
的值。foo
引用了一个函数。foo();
0
,然后是1
、2
等。1
、2
、3
吗?你已经走在了正确的轨道上,但在这种情况下,这个结论不成立的原因是因为前增量和后增量之间的区别(++var
vs var++
)。它们的区别在于前增量的结果是变量增加后的值,而后增量的结果是变量增加前的值。0
,递增的 结果 是 1
,但返回值是原始值 0
。如果是 ++x
,则会得到 1
、2
等。 - Nick Craver让我们分解一下...首先,我们定义一个匿名函数:
(function() { ... })
(function() { ... })()
function(){return x++;}
当我们创建上述函数时,闭包捕获了x=0。然后我们将这个结果函数分配给foo:
var foo = function(){return x++;}
闭包捕获了变量x的值。每当执行foo时,x都会增加。
立即调用的匿名函数,后面跟随()
(不传递参数)。当执行该函数时,它会返回另一个函数,该函数有自己的x
变量,运行时会递增。
因此,由于创建它的x
继续增加,所以foo()
第一次运行将是0
,第二次运行将是1
等。
实际上,在这种情况下,x
是分配给foo
对象的块/闭包中的局部变量。每次调用foo()
时都会增加一个。
在http://jsfiddle.net/3X283/中查看它的运行情况。
这就是所谓的闭包,其中定义了两个函数 - 内部函数(即闭包)和外部函数,后者创建并返回闭包。
您的代码立即调用外部函数,并将结果(闭包)分配给foo
。
请注意,闭包内部的代码不包括语句var x = 0;
,因此当您调用foo()
时,它仅执行闭包内部的代码(return x++;
)。
这里引用的x
是在调用中实例化的。闭包有趣的地方在于,这个x在外部函数的调用之间是不同的 - 请考虑下面的示例。foo和bar将独立增加,因为它们引用不同的x
。
function makeClosure(){
var x = 0;
return function(){return x++;};
}
var foo = makeClosure();
var bar = makeClosure();
foo(); //returns 0
foo(); //returns 1
bar(); //returns 0
foo(); //returns 2