JavaScript闭包与匿名函数 - JavaScript closures vs. anonymous functions

语言: CN / TW / HK

问题:

A friend of mine and I are currently discussing what is a closure in JS and what isn't.我的一个朋友和我目前正在讨论JS中的闭包,什么不是闭包。 We just want to make sure we really understand it correctly.我们只想确保我们真正正确地理解了它。

Let's take this example.让我们来看这个例子。 We have a counting loop and want to print the counter variable on the console delayed.我们有一个计数循环,并希望延迟在控制台上打印counter变量。 Therefore we use setTimeout and closures to capture the value of the counter variable to make sure that it will not print N times the value N.因此,我们使用setTimeout闭包来捕获计数器变量的值,以确保它不会输出N倍于值N的值。

The wrong solution without closures or anything near to closures would be:没有闭包或接近闭包的错误解决方案是:

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

which will of course print 10 times the value of i after the loop, namely 10.这当然会在循环后输出i 10倍的值,即10。

So his attempt was:因此,他的尝试是:

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

printing 0 to 9 as expected.按预期打印0到9。

I told him that he isn't using a closure to capture i , but he insists that he is.我告诉他,他没有使用闭包捕获i ,但他坚持认为自己是。 I proved that he doesn't use closures by putting the for loop body within another setTimeout (passing his anonymous function to setTimeout ), printing 10 times 10 again.我通过将for循环体放在另一个setTimeout (将他的匿名函数传递给setTimeout )中,再次打印10乘10来证明他没有使用闭包 The same applies if I store his function in a var and execute it after the loop, also printing 10 times 10. So my argument is that he doesn't really capture the value of i , making his version not a closure.如果我将他的函数存储在var并在循环执行它,并打印10次10​​,则同样适用。所以我的观点是他并没有真正捕获i的值,因此他的版本不是闭包。

My attempt was:我的尝试是:

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

So I capture i (named i2 within the closure), but now I return another function and pass this around.因此,我捕获了i (在闭包中命名为i2 ),但是现在我返回了另一个函数并将其传递给周围。 In my case, the function passed to setTimeout really captures i .就我而言,传递给setTimeout的函数实际上捕获了i

Now who is using closures and who isn't?现在谁在使用闭包,谁没有?

Note that both solutions print 0 to 9 on the console delayed, so they solve the original problem, but we want to understand which of those two solutions uses closures to accomplish this.请注意,这两种解决方案在控制台上都延迟输出0到9,因此它们可以解决原始问题,但是我们想了解这两种解决方案中的哪一种使用闭包来完成此任务。


解决方案:

参考一: https://stackoom.com/question/sFkm
参考二: JavaScript closures vs. anonymous functions
「其他文章」