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

时间:2012-06-26 03:06:25

标签: javascript jquery

我试图解开代码

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?

3 个答案:

答案 0 :(得分:4)

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

它的目的是为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的不同值为循环的每次迭代生成并返回一个函数。

答案 1 :(得分:2)

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

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

除了风格上的原因和个人选择之外,我没有理由选择其中一种。

答案 2 :(得分:1)

  

&#34;请查看更新后的问题,说明我感到困惑的地方&#34;

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

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

setTimeout(someFunc, 100);

注意someFuncsetTimeout作为参数传递给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的实际参数。当时间到时,它将返回将要执行的函数。因为返回的(内部)函数是在(外部)匿名函数的范围内定义的,所以它可以访问{{1}}参数。