2010-05-10 48 views
14

我對JS比較新,所以這可能是一個常見問題,但我在處理for循環和onclick函數時發現了一些奇怪的問題。我能夠使用此代碼複製的問題:用於循環索引奇怪的JavaScript

<html> 
<head> 

<script type="text/javascript"> 
window.onload = function() { 
    var buttons = document.getElementsByTagName('a'); 
    for (var i=0; i<2; i++) { 
     buttons[i].onclick = function() { 
      alert(i); 
      return false; 
     } 
    } 
} 

</script> 

</head> 

<body> 
<a href="">hi</a> 
<br /> 
<a href="">bye</a> 

</body> 

</html> 

當點擊我期望得到的鏈接「0」和「1」,而是我得到「2」對他們倆的。爲什麼是這樣?

順便說一句,我設法通過使用「this」關鍵字來解決我的特殊問題,但我仍然對這種行爲背後的問題感到好奇。

+0

請舉例說明如何用「this」解決問題。 – 2017-02-17 19:05:11

回答

14

您在for循環中有a very common closure problem

閉包中的變量共享相同的單個環境,因此在執行onclick回調時,循環已經運行,i變量將指向最後一個條目。

你可以用更倒閉解決這個問題,使用函數工廠:

function makeOnClickCallback(i) { 
    return function() { 
     alert(i); 
     return false; 
    }; 
} 

var i; 

for (i = 0; i < 2; i++) { 
    buttons[i].onclick = makeOnClickCallback(i); 
} 

這可以說是相當棘手的話題,如果你不熟悉閉包是如何工作的。您可以檢查出以下Mozilla的文章作一簡要介紹:


注:我也建議不要使用varfor循環中,因爲這可能會欺騙你相信i變量具有塊範圍,另一方面,i變量就像變量buttons一樣,在該函數中作用域。

0

這是執行問題的順序

How to assign event callbacks iterating an array in javascript (jQuery)

基本上,單擊處理程序訪問i好後退出循環,因此i等於2

+0

這也是一個範圍問題,當我不明白它應該的時候,「我」正在徘徊。 – Greg 2010-05-10 14:32:14

+0

沒錯,這就是爲什麼我把我的一篇關於封閉的帖子聯繫起來。 – 2010-05-10 14:39:23

9

您需要存儲i變量的狀態,因爲在事件觸發時,i的作用域狀態已增加到最大循環計數。

window.onload = function() { 
    var buttons = document.getElementsByTagName('a'); 
    for (var i=0; i<2; i++) { 
     (function (i) { 
      buttons[i].onclick = function() { 
       alert(i); 
       return false; 
      } 
     })(i); 
    } 
} 

上面示例創建一個參數i,然後將其與被i作爲參數傳遞稱爲匿名函數。這將在單獨的作用域中創建一個新變量,並將該值保存爲特定迭代時的值。

+1

不建議在循環中創建函數 – 2014-05-06 02:07:50

+0

@Ryan:我不確定這是否是單調乏味或混亂的說話。您正在重複JSLint/JSHint警告,而沒有花時間理解它的含義。看看[docs](http://www.jshint。com/docs/options /#loopfunc)作爲不應在循環中創建的函數的示例。 IIFEs是可以接受的,因爲在某些情況下它幾乎是唯一的選擇,直到'let'被普遍支持。接受的答案也可以在循環中創建函數,但不會在那裏投票或評論,但是? – 2014-05-06 07:05:21

+0

好的,讓我澄清一下:你正在循環中創建*兩個*函數。 IIFE和點擊處理程序。接受的答案是在循環中創建一個函數:點擊處理程序。因此,接受的答案可以最大限度地降低效率低下的問題。 – 2014-05-06 14:51:01