2013-08-23 73 views
0

學習Javascript並不能弄清楚爲什麼這兩個函數是不同的。我看到這個例子(我給函數添加了名字):學習Javascript,爲什麼這兩個函數的行爲有所不同?

var txt = ["a","b","c"]; 

for (var i = 0; i < 3; ++i) {  
    setTimeout((function myBind(msg) { 
     return function myAlert() { alert(msg); } 
    })(txt[i]), 1000);   
}​ 

我看到一個調用alert的函數正在返回。所以我想,爲什麼不直接把它直接返回:

var txt = ["a","b","c"]; 

for (var i = 0; i < 3; ++i) {  
    setTimeout(function() { alert(txt[i]);} ,1000);   
}​ 

這最終警告'未定義。我知道這是因爲它試圖訪問txt [3],因爲一秒後循環結束,我已設置爲3,但我不明白原始設置如何避免此問題。

+1

研究閉包以及如何使用這個概念來控制變量的範圍。應該以正確的方向啓動你。 – deostroll

+0

常見問題;傳遞函數而不是傳遞閉包。在爲事件處理程序傳遞函數時也使用它。關於閉包的很好的解讀:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures – HMR

回答

1

實施例1

封閉件執行瞬間腳本,並且還允許傳遞內部 一個參數,該參數被存儲和保持存儲該函數內部打印功能內部的i值。參數==參數

(function(param){})(parameter) 

在你的例子中,該函數返回的另一個函數將由setTimeout執行。

(function(param){ 
return function(){ 
    alert(param) 
} 
})(parameter) 

而且當您將參數先前傳遞給函數時,它將返回正確的值。

例2

的setTimeout的被稱爲3倍速度非常快,但該參數不存儲 所以它需要的最後一個值從TXT &知道我和循環結束執行setTimeout的前值爲3


基本上在第一個示例中,您將每個txt [i]存儲在使用這些閉包創建的每個函數中。

在第二個你不存儲txt [i]的任何地方。你只需告訴setTimout函數來提醒txt [i],在1秒之後它是由for循環創建的最後一個函數。

+0

我不明白味精如何活到最後。 myAlert被setTimeOut引用,但沒有引用myBind。不應該垃圾收集拾取myBind ...因此也摧毀myAlert? – Alex

0

在第一個版本中,txt[i]已被綁定到一個新變量msg,該變量是創建的每個function的不同位置。

在第二個版本中,ifunction中的每一個位置相同,因爲i的範圍更大;每次通過循環都不會創建新的i變量。

+0

所以有3個獨立的函數存儲在內存中?所以他們看起來像這樣:'function(){alert('a');} function(){alert('b')} function(){alert('c');}'那些被認爲是動態函數嗎? – Alex

+0

@Alex有3個不同的功能對象,正確的。這些函數對象的_body_(代碼)是相同的,但是每次綁定到一個不同的對象的'msg'。正如其他人所說的那樣,這些都是封閉的(如果最初可以幫助你理解它們,我想你可以考慮關閉「動態函數」)。 –

0

這是一個併發問題。

setTimeout爲每次執行創建一個「線程」,但在超時過期之前不會計算該函數。

因此,第一次超時後,您的for循環已結束(i的值爲3),因此訪問txt[i]時返回未定義。 嘗試用console.log

相關問題