1. 程式人生 > >JS閉包導致迴圈給按鈕新增事件時總是執行最後一個

JS閉包導致迴圈給按鈕新增事件時總是執行最後一個

今天再做需求時有一個功能是這樣的,就是有不定個的按鈕,且點選按鈕時都需要執行一個方法(引數不一樣)

那麼我很自然的就想到了,迴圈給每個按鈕新增事件和引數就好了,由於不方便上傳系統程式碼,下面以一個簡單例子來說明.

<pre name="code" class="html"><html>
<body>
<ul id="list">  
<li>按鈕1</li>  
<li>按鈕2</li>  
<li>按鈕3</li>  
<li>按鈕4</li>  
<li>按鈕5</li>  
</ul>    
</body>
</html>


比如現在要實現這麼一個功能,在頁面上點選上面的按鈕1到按鈕5時分別alert出1,2,3,4,5.

那麼很多人自然想到如下這麼做:

加入如下指令碼程式碼:

<script>  
var list_obj = document.getElementsByTagName('li');  
for (var i = 0; i <= list_obj.length; i++) {        
  list_obj[i].onclick = function() {      
    alert(i);      
  }  
}
</script>  


執行後,奇怪的發現無論點選那個li標籤,alert出的都是最後一個的內容,5

下面做下分析:因為在for迴圈裡面指定給list_obj[i]

.onclick的事件處理程式,也就是onclick那個匿名函式是在for迴圈執行完成後(使用者單擊連結時)才被呼叫的。而呼叫時,需要對變數i求值,解析程式首先會在事件處理程式內部查詢,但i沒有定義。然後,又到方法外部去查詢,此時有定義,但i的值是4(只有i大於4才會停止執行for迴圈)。因此,就會取得該值——這正是閉包(匿名函式)要使用其外部作用域中變數的結果。而且,這也是由於匿名函式本身無法傳遞引數(故而無法維護自己的作用域)造成的。

那現在原因是知道了,如何來避免這種情況呢?

既然已經知道函式呼叫外部變數的時候就構成了一個閉包,裡面的變數會受到別的地方的影響,那麼我們

現在要做的就是,構建一個只有自己本身才可訪問的閉包,儲存只供本身使用的變數

構建一個閉包很簡單,程式碼如下:

方式一:

var list_obj = document.getElementsByTagName('li');  
for (var i = 0; i <= list_obj.length; i++) {
<span style="white-space:pre">	</span>list_obj[i].onclick = (function(i){ // outer function
<span style="white-space:pre">			</span>return function(){ //inner function
<span style="white-space:pre">				</span>alert(i);
<span style="white-space:pre">			</span>};
<span style="white-space:pre">	</span>})(i);  
}* 

方式二:

var list_obj = document.getElementsByTagName('li');  
for (var i = 0; i <= list_obj.length; i++) {  
   
   (function(i){
		//var p = i    
		list_obj[i].onclick = function() {      
			alert(i);      
		}
   })(i);
} 



現在再執行就能得到我們想要的效果了。