簡體   English   中英

使用for循環的addEventListener給我一個不確定的結果

[英]addEventListener using for loop gives me an undefined result

為什么這段代碼給我一個不確定的結果? 我已經在網絡瀏覽器中進行了測試。 它告訴我li [i]是未定義的。 而且我不知道為什么以及如何。 我知道關閉。 也許每次我單擊每個li元素時,它都應該彈出字符串“ dataToggle”。 但是有人可以幫助我提供有關此特定問題的更多詳細信息,您認為理解該問題重要的是什么? 謝謝

 (function(){ var innerDiv = document.getElementsByClassName('showDiv')[0]; //var li = document.querySelectorAll('ul.idiv li'); var li = document.getElementsByTagName('li'); for(var i=0,len=li.length; i<len; i++){ li[i].addEventListener('click',function(e){ e.preventDefault(); alert(li[i]); var data = li[i].dataset.info; showDiv.innerHTML = data; },false); } }()); 
 <div class="showDiv">Show data: </div> <div class="outerDiv"> <ul class="idiv"> <li data-info="datashow"><a href="">111</a></li> <li data-info="dataHide"><a href="">222</a></li> <li data-info="dataToggle"><a href="">333</a></li> </ul> </div> 

這是因為, i是在事件處理程序函數外部定義的變量,每次迭代都會遞增。 因此,當您完成for循環的迭代時, i的值等於len ,這將導致li[i] undefined 而且,如果您問我為什么在迭代過程中不考慮它的值,那是因為您的事件處理程序功能僅在事件發生時才執行(而不是在您通過for循環設置事件處理程序時執行)。 因此,您可以在函數范圍內創建一個變量,該變量不會被迭代更改。 最好從事件處理程序內部使用this來獲得相同的結果。

for(var i=0,len=li.length; i<len; i++){
   li[i].addEventListener('click',function(e){
         e.preventDefault();
         alert(this);
         var data = this.dataset.info;
         showDiv.innerHTML = data;
   },false);
} 

了解for循環

為什么在for循環結束后i的值等於len 讓我們用一個簡單的例子來使您了解情況。

var len = 2;
for(var i=0; i<len; i++; {
    //Do anything here
}
console.log("after for loop: i = " + i);

讓我們來看一下迭代。

  1. i = 0 ,匹配條件i<len ,條件繼續執行代碼塊,然后執行i++ ,使i=1
  2. 現在i = 1 ,匹配條件i<len ,條件執行代碼塊,然后執行i++ ,這使i=2
  3. 現在i = 2 ,無法滿足條件i<len並停止迭代。

因此,在執行步驟3之前,您已經設置了i=2因此, for循環之后的最終console.log將顯示, after for loop: i = 2

發生這種情況是由於范圍。 EventListener內部,您具有匿名函數,因此,您不再在li的范圍內。 但是,您可以使用this關鍵字來引用它。 查看代碼中我已替換的警報。

 (function(){ var innerDiv = document.getElementsByClassName('showDiv')[0]; //var li = document.querySelectorAll('ul.idiv li'); var li = document.getElementsByTagName('li'); for(var i=0,len=li.length; i<len; i++){ li[i].addEventListener('click',function(e){ // you are now inside a different function block here. e.preventDefault(); alert(this.innerHTML); var data = li[i].dataset.info; showDiv.innerHTML = data; },false); } }()); 
 <div class="showDiv">Show data: </div> <div class="outerDiv"> <ul class="idiv"> <li data-info="datashow"><a href="">111</a></li> <li data-info="dataHide"><a href="">222</a></li> <li data-info="dataToggle"><a href="">333</a></li> </ul> </div> 

除了其他發布者的答案之外,另一種方法是使用具有function的局部范圍。 在JavaScript中, function是創建新范圍的最可靠方法。 以上述示例為例,

for (var i = 0; i < li.length; i++) {
    (function(i) {
        var j = i;
        li[j].addEventListener('click', function(e) {
        e.preventDefault();
        var data = li[j].dataset.info;
        showDiv.innerHTML = data;
    }, false);
  })(i);
}

我創建了一個新的作用域,它將隔離變量i的值。 如果您使用的是ES6,則可以使用let關鍵字執行相同的操作。 您要做的就是用let替換var 您還可以在for循環中使用let ,這將為您提供for循環本地的全新作用域。

您需要參考要附加事件的特定li

(function(){
      var innerDiv = document.getElementsByClassName('showDiv')[0];
       var li = document.getElementsByTagName('li'); 
          for(var i=0,len=li.length;i<len;i++){
           var thisLi = li[i];
           thisLi.addEventListener('click',function(e){
                 e.preventDefault();
                 alert(thisLi.innerHTML);
                 var data = thisLi.getAttribute('data-info');
                 innerDiv.innerHTML = data;
           },false);
      } 
    }());

click將被執行時, i值為3(在您的情況下),因此li[i]會有所不同。 您可以檢查THIS的控制台以檢查click事件中i

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM