2010-12-11 78 views
0

簡單案例:我想要加載多個具有通用名稱和後綴的圖像,例如:image0.png,image1.png,image2.png ... imageN.pngfor循環和詞彙環境中的閉包

我使用for循環簡單:

var images = []; 
for (var i=1; i<N; i++) { 
    images[i] = new Image(); 
    images[i].onload = function() { 
     console.log("Image " + i + " loaded"); 
    }; 
    images[i].src = "image" + i + ".png"; 
} 

什麼我得到的控制檯:

Image N loaded 
Image N loaded 
Image N loaded 
... 
Image N loaded 

但我想應該是這樣的:

Image 0 loaded 
Image 1 loaded 
Image 2 loaded 
... 
Image N loaded 

這是爲什麼發生? 我怎樣才能得到我想要的行爲?

+0

可能重複[關閉的Javascript內循環 - 簡單實用的例子(http://stackoverflow.com/questions/750486/javascript-closure -inside-loops-simple-practical-example) – 2010-12-11 19:40:12

回答

3

i在函數內部執行函數時執行,而不是在將它分配給onload時執行。您的for循環在您的onload函數觸發時已經完成,所以它們都會看到最終值N

要捕捉的i當前值,你需要把它作爲參數傳遞到可以被捕捉爲一個局部變量的另一個功能:

function captureI(i) { 
    return function() { 
     console.log("Image " + i + " loaded"); 
    }; 
} 

var images = []; 
for (var i=1; i<N; i++) { 
    images[i] = new Image(); 
    images[i].onload = captureI(i); 
    images[i].src = "image" + i + ".png"; 
} 

這工作,因爲每次調用captureI,一時間爲該實例創建新的局部變量captureI。本質上,您正在創建不同的變量,並且每個onload函數捕獲變量的不同實例。

+0

感謝您的最後解釋。 – 2010-12-11 18:56:52

0

您的循環計數器變量已被覆蓋。查看this常見問題解答條目,解釋其發生的原因以及如何解決該問題。

0

由於變量i被聲明爲循環範圍之外,所以在循環完成後它將保留其最終值。你創建的匿名函數都綁定到這個變量上,當它們被調用時,它們都會得到相同的最終值N

this question有很好的討論。

+0

這將爲所有圖像提供N-1 :-) – 2010-12-11 19:02:22

2

可以把它包裝在封閉,以避免使用i變量,這是一個循環變量,從而改變:

(function(j) { 
    images[i].onload = function() { 
     console.log("Image " + i + ", " + j + " loaded"); 
    }; 
})(i); 

這證明i之間的差異,這是一個循環變量和變化,並j,這是一個函數綁定的參數,它不會改變。

想在這裏看到的jsfiddle:中