使用for循环的addEventListener给了我一个未定义的结果

时间:2016-02-05 06:17:06

标签: javascript for-loop undefined

为什么这段代码会给我一个未定义的结果? 我已在网络浏览器中测试过。它告诉我li [i]是未定义的。而且我不知道为什么以及如何。 我知道关闭。也许它应该弹出字符串' dataToggle'每次我点击每个li元素;但有人可以帮助我了解这个具体问题的更多细节,以及您认为理解这个问题的重要性? 感谢



(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);
    
  } 
}()); 
&#13;
<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>
&#13;
&#13;
&#13;

4 个答案:

答案 0 :(得分:3)

这是因为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循环

为什么i循环结束后len的值等于for?让我们有一个更简单的例子让你了解情况。

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并停止迭代。
  4. 因此,在进入第3步之前,您已经设置了i=2。因此console.log循环之后的最终for会说, after for loop: i = 2

答案 1 :(得分:1)

这是因为范围。在EventListener内,您有一个匿名函数,因此,您不再属于li的范围。但是,您可以使用this关键字引用它。查看我在代码中替换的提醒。

&#13;
&#13;
(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);
    
  } 
}()); 
&#13;
<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>
&#13;
&#13;
&#13;

答案 2 :(得分:1)

除了其他海报的答案之外,另一种方法是使用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关键字执行相同的操作。您所要做的就是将var替换为let。您还可以在let循环中使用for,这将为您提供for循环本地的全新范围​​。

答案 3 :(得分:0)

您需要参考您要附加活动的特定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);
      } 
    }());

执行clicki的值为3(在您的情况下),因此li[i]会有所不同。您可以查看THIS的控制台,查看i活动中click的值