2013-08-26 98 views
5

至少是我認爲它發生在這種情況下:的JavaScript的setTimeout不能訪問功能的可調

function MyFunc() { 
    var people = Array({name: 'Alex', age: 25}, {name: 'Ellen', age: 43}); 
    for (var i=0; i<people.length; i++) { 
     setTimeout(function() { ShowIt(people[i].name) }, 1000); // !!! 
    } 
} 

function ShowIt(name) { 
    alert(name); 
} 

我得到這個錯誤Uncaught TypeError: Cannot read property 'name' of undefined,所以它看起來像setTimeout偵聽器函數內people變量不無障礙。爲什麼以及如何修復它?

+0

這是一個非常常見的錯誤,請參閱此問題:http://stackoverflow.com/questions/5226285/settimeout-in-a-for-loop-and-pass-i-as-value –

+1

不,意思是人們[i]'沒有被定義。如果'people'不在範圍內,則會出現'Uncaught ReferenceError:人員未定義'之類的內容。 –

回答

21

其實數組還行。它發生的是你的i實際上是2,並且數組中沒有第三個元素。這就是爲什麼你會得到這個錯誤。這裏是解決方案:

function MyFunc() { 
    var people = Array({name: 'Alex', age: 25}, {name: 'Ellen', age: 43}); 
    for (var i=0; i<people.length; i++) { 
     (function(i) { 
      setTimeout(function() {    
       ShowIt(people[i].name) 
      }, 1000); 
     })(i); 
    } 
} 

function ShowIt(name) { 
    console.log(name); 
} 

MyFunc(); 

下面是一個的jsfiddle http://jsfiddle.net/krasimir/XDfLu/2/

長的答案:當您使用的setTimeout你傳遞一個函數給它。這個函數將來會被調用,你在那裏做的事情也會在將來被執行。在那一刻(未來的),你的我不再是0或1.它實際上是2,因爲你的循環結束了。提供的解決方案使用額外的閉包來創建一個範圍/上下文。一旦傳遞給setTimeout的函數被調用,它就會查找一個i變量。在它的範圍內沒有這樣的事情,所以它上升一級。而且還有我們需要的實際價值。

+0

小心解釋解決方案?它是什麼?爲什麼它解決了這個問題? –

+0

編輯的答案。 (我不確定我解釋得不夠好)。 – Krasimir

+0

差不多。即使您添加了函數調用,函數是否爲閉包也無關緊要。唯一重要的是該函數被執行並通過它創建一個新的範圍。 –