Javascript:循环关闭?

IT技术 javascript closures anonymous-function
2021-02-03 03:36:37

我想做以下事情:

for (var i = 0; i < 10; ++i) {
    createButton(x, y, function() { alert("button " + i + " pressed"); }
}

这样做的问题是我总是得到 的最终值,i因为 Javascript 的闭包不是按值的。
那么我怎样才能用 javascript 做到这一点呢?

5个回答

如果您为使用 JavaScript 1.7 或更高版本的浏览器编码,一种解决方案是使用let关键字:

for(var i = 0; i < 10; ++i) {
    let index = i;
    createButton(x, y, function() { alert("button " + index + " pressed"); }
}

从 MDC 文档中心:

let 关键字导致创建具有块级作用域的 item 变量,从而为 for 循环的每次迭代创建一个新的引用。这意味着为每个闭包捕获一个单独的变量,解决共享环境带来的问题。

查看MDC 文档中心了解传统方法(创建另一个闭包)。

for(var i = 0; i < 10; i++) {
    (function(i) {
        createButton(function() { alert("button " + i + " pressed"); });
    })(i);
}

请注意,JSLint 不喜欢这种模式。它抛出“不要在循环中创建函数。”。

现场演示: http : //jsfiddle.net/simevidas/ZKeXX/

@McStretch 我明白了。更新后的demo(在Firefox中有效)在这里:jsfiddle.net/simevidas/ZKeXX/2看来我们用不了let多久了。即使 IE10 实现它,我们也必须等到 IE9 退出市场(这可能不会在 2020 年之前发生)。
2021-03-16 03:36:37
@Šime - 我刚刚看到这个问题:stackoverflow.com/questions/2356830/...,它说你必须明确告诉浏览器(现在只有 Firefox)你正在使用 1.7。这是一个更新的小提琴:jsfiddle.net/simevidas/ZKeXX/1很蹩脚吧?显然,除非每个人都支持 1.7 或更高版本,否则这不是一个真正好的解决方案,谁知道什么时候会发生。
2021-04-02 03:36:37
由于它的清洁,我比彼得更喜欢这个答案。不过,如果更多浏览器支持该let关键字,那就太好了
2021-04-03 03:36:37
@McStretch 我试图let在 jsFiddle 中制作一个演示,但我无法让它工作。请参见此处:jsfiddle.net/simevidas/ZKeXX/1 Firefox 4 引发错误。
2021-04-04 03:36:37

通过执行另一个函数为闭包创建一个新的作用域:

for(var i = 0; i < 10; ++i) {
    createButton(x,y, function(value) { return function() { alert(...); }; }(i));
}

http://www.mennovanslooten.nl/blog/post/62

1. 您可能希望在 return 语句的末尾放置一个分号,以使代码更具可读性。2. IIFE 通常用括号括起来。
2021-03-30 03:36:37

您需要将闭包放入一个单独的函数中。

for(var dontUse = 0; dontUse < 10; ++dontUse) {
    (function(i) {
        createButton(x, y, function() { alert("button " + i + " pressed"); }
    })(dontUse);
}

此代码创建了一个匿名函数,该函数i将循环的每次迭代作为参数。
由于这个匿名函数i每次迭代都有一个单独的参数,它解决了这个问题。

这相当于

function createIndexedButton(i) {
    createButton(x, y, function() { alert("button " + i + " pressed"); }
}

for(var i = 0; i < 10; ++i) {
    createIndexedButton(i);
}
for(var i = 0; i < 10; ++i) {
    createButton(x, y, (function(n) {
        return function() {
            alert("button " + n + " pressed");
        }
    }(i));
}

外部的匿名函数会被自动调用,并n在其作用域内创建一个新的闭包每次调用时都会获取当时的当前i