2014-11-01 166 views
1

我做了一些研究後放棄了這一點。我的問題如下:Javascript關閉與循環

post,我瞭解以下代碼。

var funcs = {}; 
for (var i = 0; i < 3; i++) {   // let's create 3 functions 
funcs[i] = function() {   // and store them in funcs 
    var item = "item" + i;   // inside 
    console.log("item: " + item + ", i: " + i); // each should log its value. 
    }; 
} 
for (var j = 0; j < 3; j++) { 
    funcs[j]();      // and now let's run each one to see 
} 

Result: 
item: item3, i: 3 
item: item3, i: 3 
item: item3, i: 3 

但如果我更改移動var item = "item" + i之外的功能(),結果會有所不同。爲什麼是這樣?

var funcs = {}; 
for (var i = 0; i < 3; i++) {   // let's create 3 functions 
    var item = "item" + i;    // outside 
    funcs[i] = function() {   // and store them in funcs 
     console.log("item: " + item + ", i: " + i); // each should log its value. 
    }; 
} 
for (var j = 0; j < 3; j++) { 
    funcs[j]();      // and now let's run each one to see 
} 

Result: 
item: item2, i: 3 
item: item2, i: 3 
item: item2, i: 3 
+0

真正的問題是你的聲明和'i'變量的用法。它保持在最高級別的範圍內,但是您可以在關閉中使用它。當你「關閉」,現在讓我們跑......「。那麼'i'變量(用於for(;;)將會完成它的循環並且顯示值 – 2014-11-01 09:38:44

回答

1

你面臨的關鍵問題是一個閉包通過引用而不是按值來捕獲變量。例如:

var i = 0; 
var f = function(){ i++; console.log(i); } 
var g = function(){ i++; console.log(i); } 
f(); g(); f(); g(); 

這將顯示1,2,3,4,因爲fg和不捕獲變量i的值,但變量本身,因此都突變相同的變量。

一個非常常見的錯誤是創建在一個循環中的多個閉合忘記他們都將捕獲相同的變量(在循環中使用的一個),因此,當這個環路變量被遞增所有已創建的封閉件將看到它的變化。例如,在你的代碼

for (var i = 0; i < 3; i++) { 
    funcs[i] = function() { 
     var item = "item" + i; // inside 
     console.log("item: " + item + ", i: " + i); 
    }; 
} 

item是一個局部變量的函數,但i,而不是來自於外界,它的所有的人共享。由此可以看出,例如與

i = 42; 
funcs[0](); funcs[1](); funcs[2](); // Displays 42 three times 
i = 99; 
funcs[0](); funcs[1](); funcs[2](); // Now they all display 99 

在你的問題的東西第二種情況下都只是略有不同,因爲在

for (var i = 0; i < 3; i++) { 
    var item = "item" + i; 
    funcs[i] = function() { 
     console.log("item: " + item + ", i: " + i); 
    }; 
} 

item變量現在共享,因爲它的定義功能外並關閉它捕獲它。在顯示屏中,您可以看到分配給它的最後一個值。

關鍵的一點是要記住,在Javascript中的變量是本地的功能,不是本地的{...}塊(像它在C++例如),並因此鑑別因素是,如果變量的函數內聲明或者在函數之外,如果它們是在循環內部或外部聲明的話。

爲了克服這個共同的問題,併爲每個中的迴路形成的封閉的單獨的索引你經常會看到這樣

var f = (function(i){return function(){ ... };})(i); 

其中創建函數,立即調用返回另一個函數的代碼。

的原因是創建一個單獨的新變量的唯一方法是一個功能,留給我們創建一個返回函數的函數的模式:在這種情況下有用的閉合(內)將捕獲每個迭代的變量都不相同(因爲它是外部參數)。

改變你的代碼

for (var i = 0; i < 3; i++) { 
    funcs[i] = (function(i){return function() { 
     var item = "item" + i; 
     console.log("item: " + item + ", i: " + i); 
    };})(i); 
} 

可以發揮預期的(即每個函數現在有自己的i值)。

+0

謝謝。但是,請問你回答這個問題:什麼是我的代碼1和2之間的區別是什麼?爲什麼把'var item'放在循環之外會產生影響? – 2014-11-04 21:54:07

+1

@ls .:問題不在循環外部,而是在**函數內部或外部**。除了函數外,它是一個由所有函數共享的變量,如果它在函數內部,那麼它是每個函數的不同變量。 – 6502 2014-11-04 22:26:31

+0

我想我已經得到了它!如果你可以添加這個評論,即'如果項目在外面。 ..如果它在你的答案裏面......「我會投票給它作爲答案。 (因爲我真的沒有得到你的原始答案)。非常感謝 – 2014-11-06 01:05:58

0

item變量不存在,直到函數的第一種情況下運行時,在該點它是本地的每個功能和獲取設置等於"item" + i。而i3,因爲它在外部範圍內聲明,3是循環結束時的情況。

在第二種情況下,item變量存在於功能包含範圍 - 的相同的範圍內i - 和所述第一循環的最後迭代期間已被設定到"item2"。在該循環中,i的值爲0,1,2 - 循環結束時僅設置爲3

+0

我還是不明白在第二種情況下,爲什麼我在'console.log() '得到3這是循環結束時的值,而我在'item'得到2,這是最後一次迭代的值?是什麼引起這種差異的主要問題以及爲什麼? – 2014-11-01 11:40:31