4

我正在尝试理解代码

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?
4

3 回答 3

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 使用的函数。正在为循环的每次迭代使用不同的值生成并返回一个函数 for i

于 2012-06-26T03:09:07.070 回答
2

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

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

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

于 2012-06-26T03:10:12.460 回答
1

“您能否检查更新的问题,说明我在哪里感到困惑”

好的,这里是解释。请记住,第一个参数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参数。

于 2012-06-26T04:19:11.983 回答