2011-04-05 190 views
5

我喜欢做的事情大致如下:Javascript:关闭循环?

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

的这个是,我总是得到的i终值,因为Javasript的关闭是没有价值的。
那么我怎样才能做到这一点与JavaScript?

+0

您可以编辑createButton,允许它传递另一个参数,即i。这样你可以将我存储在你的createButton函数中并使用它。 – rsplak 2011-04-05 16:55:09

+0

[Javascript闭包内循环 - 简单实用示例]的可能重复(http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – rds 2013-01-17 17:53:41

回答

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

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

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

+0

因为它的清洁,我比Peter更喜欢这个答案。如果更多浏览器支持'let'关键字,那将会很好。 – McStretch 2011-04-05 17:13:20

+0

@McStretch我试图在jsFiddle中做一个'let'演示,但是我无法让它工作。看到这里:http://jsfiddle.net/simevidas/ZKeXX/1/ Firefox 4会引发错误。 – 2011-04-05 17:31:03

+0

@Šime - 我刚刚看到这个问题:http://stackoverflow.com/questions/2356830/what-browsers-currently-support-javascripts-let-keyword,它说你必须明确地告诉浏览器(Firefox现在只有现在)你使用的是1.7。这是一个更新的小提琴:http://jsfiddle.net/simevidas/ZKeXX/1/。很蹩脚吧?显然,直到每个人都支持1.7或更高版本,并且知道何时会发生,这不是一个很好的解决方案。 – McStretch 2011-04-05 17:52:54

1

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

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

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

这相当于

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

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

在外面的匿名功能将自动调用并在其范围内,在那里,它利用每个i然后当前值创建具有n一个新的闭合它被调用的时间。

4

通过执行另一个函数创建关闭一个新的范围:

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

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

+0

1。您可能希望在return语句的末尾放置一个分号,以使代码更具可读性。 2. IIFE通常包裹在parens中。 – 2011-04-05 17:02:18

+0

@Šime,是的,我同意。 – 2011-04-05 17:07:30

7

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

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

从MDC文件中心:

let关键字导致项目 变量与块0一起创建级别作用域,导致为for循环的每次迭代 创建一个新的引用 。这意味着每个 闭包都会捕获一个单独的变量,从而解决共享环境造成的问题。

查看MDC Doc Center的传统方法(创建另一个闭包)。