2011-04-05 231 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的傳統方法(創建另一個閉包)。