从匿名包装器返回一个函数?

我试图理解代码

for(var i = 0; i < 10; i++) { setTimeout((function(e) { return function() { console.log(e); } })(i), 1000) } 

从这里http://bonsaiden.github.com/JavaScript-Garden/#function.closures

我理解这种方法:

 for(var i = 0; i < 10; i++) { (function(e) { setTimeout(function() { console.log(e); }, 1000); })(i); } 

有人可以通过解释第一个来帮助我吗?

我将尝试解释我如何理解第一个,

 first i is 0, setTimeout is called, self calling function "function(e)" is called with i=0, Im stuck!! what happens when this function returns a function? 

“你可以查看更新的问题,指明我在哪里感到困惑”

好的,这是一个很长的解释。 请记住, setTimeout()的第一个参数需要是对指定延迟后要执行的函数的引用。 最简单的情况是命名一个在别处定义的函数:

 function someFunc() { console.log("In someFunc"); } setTimeout(someFunc, 100); 

注意someFunc在将其作为参数传递给setTimeout时没有括号,因为需要对函数本身的引用。 对比:

 setTimeout(someFunc(), 100); // won't work for someFunc() as defined above 

使用括号,它调用 someFunc()并将其返回值传递给setTimeout 。 但是我对someFunc()定义并没有明确地返回一个值,所以它隐式返回undefined – 这就像说setTimeout(undefined, 100)

但是如果更改someFunc()以返回函数而不是返回undefined它会起作用:

 function someFunc() { return function() { console.log("In the function returned from someFunc"); }; } 

所以现在(最后)我们来看你问题的代码:

 setTimeout((function(e) { return function() { console.log(e); } })(i), 1000) 

它不是通过名称引用函数并将其称为someFunc(i)而是定义一个匿名函数并立即将其作为(function(e) {})(i)调用。 该匿名函数返回另一个函数,它返回的函数成为setTimeout()的实际参数。 当时间到了,那就是将要执行的返回函数。 因为返回的(内部)函数是在(外部)匿名函数的范围内定义的,所以它可以访问e参数。

所有第一个做的是返回一个在超时发生后调用的函数。

它的目的是为for循环的每次迭代创建一个子范围,以便每次迭代都不会覆盖递增i

更多解释:

让我们把它分成两个不同的部分:

 for(var i = 0; i < 10; i++) { setTimeout((function(e) { return function() { console.log(e); } })(i), 1000) } 

这是第一篇:

 for(var i = 0; i < 10; i++) { setTimeout(function(){ console.log(i); //9-9 },1000); } 

现在,当你运行这个循环时,你将总是得到包含9而不是0到9的console.log()。这是因为每个setTimeout都使用与i相同的引用。

如果将setTimeout的一部分包装在匿名函数中,它会为每次迭代创建一个范围,允许每个setTimeout拥有它自己的i值。

 for(var i = 0; i < 10; i++) { setTimeout((function(i) { return function() { console.log(i); // 0-9 } })(i), 1000) } 

setTimeout中的外部函数立即执行,第一次迭代的i为0,第二次为1,等等。然后该函数返回一个函数,该函数是setTimeout使用的函数。 正在使用i的不同值为循环的每次迭代生成并返回函数。

两者都得到相同的结果:使用要调用的函数调用setTimeout,该函数在控制台上写入0到9之间的数字。 两者都使用嵌套函数将i的当前值放入闭包中,因此最终不会记录10 9。

第一个代码选择让函数返回setTimeout将调用的函数。 第二个更改嵌套顺序,以便关闭函数调用setTimeout本身。 净效果是一样的。

除了风格和个人选择,我没有理由选择其中一个。