19

我已经在 for 循环中看到匿名函数在一两个地方诱导网络上的新范围,并且想知道它是否有意义。

例如:

var attr, colors = ['green','blue','red'];

for ( attr = 0; attr < colors.length; attr++) {
    (function() {
        var colorAttr = colors[attr];

        // do something with colorAttr
    })();
}

我知道这与保持 for 循环内的范围清洁有关,但在什么情况下这是必要的?在需要在 for 循环中声明新 var 的任何地方都这样做是一种好习惯吗?

4

2 回答 2

39

2021 更新

var曾经是声明变量的唯一方法。但是我们现在拥有constlet以更好的方式解决了这个问题。这些变量声明确实将循环视为要绑定的范围,这意味着以下代码段可以正常工作,并且不需要匿名函数来捕获这些值。

const colors = ['green', 'blue', 'red'];

for (let i = 0; i < colors.length; i++) {
    const color = colors[i];
    setTimeout(function() {
        alert(color);
    }, i * 1000);
}

以下是我在 2012 年对这个问题的原始回答。


当您有没有立即执行的内部函数时,作为循环的一部分。

var i, colors = ['green', 'blue', 'red'];

for (i = 0; i < colors.length; i++) {
    var color = colors[i];
    setTimeout(function() {
        alert(color);
    }, i * 1000);
}

// red
// red
// red

即使var color在循环内部,循环也没有范围。实际上,每个循环迭代都使用一个变量。因此,当超时触发时,它们都使用相同的值,即循环设置的最后一个值。

var i, colors = ['green', 'blue', 'red'];

for (i = 0; i < colors.length; i++) {
    (function(color) {
        setTimeout(function() {
            alert(color);
        }, i * 1000);
    })(colors[i]);
}

// green
// blue
// red

这个将每次迭代的值捕获到函数的参数中,这确实创建了一个范围。现在每个函数都有自己的变量版本,该color变量在以后执行该循环中创建的函数时不会改变。

于 2012-12-20T17:08:53.973 回答
3

您快到了。如果您将值作为参数传递给您的自调用函数,那么它仅在您的代码段中才有意义。这样,它可以将该变量存储在它自己的范围对象中attr

(function( attr ) {
    var colorAttr = colors[attr];

    // do something with colorAttr
})( attr );

现在,激活对象分别是词法环境记录(它们是 ES3 和 ES5 范围对象)将有一个条目,用于表示后面的任何值attr,因此,它的closed

于 2012-12-20T17:07:11.820 回答