js中for循環點擊事件(閉包)


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title></title>
<script type="text/javascript">
function onMyLoad(){
var arr = document.getElementsByTagName("p");
for(var i = 0; i < arr.length; i++){
arr[i].onclick = function(){
alert(i);//5次均輸出5
}
}
}
</script>
</head>
<body "onMyLoad()">
<p>0</p>
<p>1</p>
<p>2</p>
<p>3</p>
<p>4</p>
</body>
</html>
以上代碼期望依次輸出0,1,2,3,4,實際卻輸出5,5,5,5,5,這是因為閉包導致,下來來具體介紹:
for循環是一個外部閉包,依次綁定的點擊事件是一個函數實例,也產生了一個閉包域,它引用了外部閉包的變量i,外部閉包域中i的最終值為5,點擊事件觸發時引用外部閉包變量i(此時i=5),所以輸出的值全為5。

解決方案
方法一:增加若干個對應的閉包域空間(采用匿名函數實現)專門用來存儲原先需要引用的內容(下標值),只限於基本類型(基本類型值傳遞,對象類型引用傳遞)

for(var i = 0; i<arr.length; i++){
(function (arg){//這個函數對象有一個本地私有變量arg(形參),該函數的function scope的closure對象屬性有兩個引用:arr和i。i的值隨外部改變,但是本地的私有變量(形參)arg不會受影響,其值在一開始被調用時就決定了
arr[i].onclick = function () {//onclick函數實例的function scope的closure對象屬性有一個引用arg
alert(arg);//只要外部空間的arg不變,這里的引用值就不會改變
}
})(i);//立即執行匿名函數,傳遞下標i(實參)
}

方法二:將下標作為對象屬性(name:“i”,value:i的值)添加到每個數組項(p對象)中

for(var i=0; i<arr.length; i++){
//為當前數組項(當前p對象)添加一個名為i的屬性,值為循環體i變量的值
//此時當前p對象的i屬性並不是對循環體的i變量的引用,而是一個獨立p對象的屬性,屬性值在聲明的時候就確定了
arr[i].i = i;
arr[i].onclick = function (){
alert(this.i);
}
}

方法三:增加若干個對應的閉包域空間用來存儲下標。新增的匿名閉包空間內完成事件綁定。

//綁定的函數中的function scope中的closure對象的引用arg是指向將其返回的匿名函數的私有變量arg
for(var i = 0; i<arr.length; i++){
arr[i].onclick = (function(arg){
return function () {
alert(arg);
}
})(i);
}
方法四:使用ES6的let關鍵字

"use strict";
var arr = document.getElementsByTagName("p");
for(var i = 0; i<arr.length; i++){
let j = i;//塊級變量
arr[i].onclick = function () {
alert(j);
}
}
---------------------
原文:https://blog.csdn.net/sinat_40172076/article/details/87161221


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM