简体   繁体   English

使用for循环的addEventListener给我一个不确定的结果

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

Why does this piece of code give me a result of undefined? 为什么这段代码给我一个不确定的结果? I have tested in the web browser. 我已经在网络浏览器中进行了测试。 It shows me that li[i] is undefined. 它告诉我li [i]是未定义的。 And I don't know why and how. 而且我不知道为什么以及如何。 I know about closure. 我知道关闭。 And maybe it should pop out the string 'dataToggle' every time I click each li element; 也许每次我单击每个li元素时,它都应该弹出字符串“ dataToggle”。 But someone could help me with more details about this specific question and what you think is important in understanding this question? 但是有人可以帮助我提供有关此特定问题的更多详细信息,您认为理解该问题重要的是什么? Thanks 谢谢

 (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> 

This is because, i is a variable defined outside your event handler function, which is incremented by each iteration. 这是因为, i是在事件处理程序函数外部定义的变量,每次迭代都会递增。 So when you finish the iterations of the for loop, the value of i is equal to len , which causes li[i] to be undefined . 因此,当您完成for循环的迭代时, i的值等于len ,这将导致li[i] undefined And if you ask me why it's value is not considered during the iteration, it's because your event handler function is only executed when the event occurs (not when you are setting the event handlers by for loop). 而且,如果您问我为什么在迭代过程中不考虑它的值,那是因为您的事件处理程序功能仅在事件发生时才执行(而不是在您通过for循环设置事件处理程序时执行)。 So you can make a variable inside the function scope which won't be changed by iteration. 因此,您可以在函数范围内创建一个变量,该变量不会被迭代更改。 Better use this from inside the event handler to get the same thing. 最好从事件处理程序内部使用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);
} 

Understanding the for loop 了解for循环

Why the value of i is equal to len after for loop is finished? 为什么在for循环结束后i的值等于len Let's have a simpler example to make you understand the situation. 让我们用一个简单的例子来使您了解情况。

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

Lets's go through the iterations. 让我们来看一下迭代。

  1. i = 0 , matches the condition i<len , which proceeds with executing the code block and executes i++ after that, which makes i=1 ; i = 0 ,匹配条件i<len ,条件继续执行代码块,然后执行i++ ,使i=1
  2. i = 1 now, matches the condition i<len , which proceeds with executing the code block and executes i++ after that, which makes i=2 ; 现在i = 1 ,匹配条件i<len ,条件执行代码块,然后执行i++ ,这使i=2
  3. i = 2 now, fails to match the condition i<len and stops the iteration. 现在i = 2 ,无法满足条件i<len并停止迭代。

So, you have set the i=2 before you go to step 3. So your final console.log after for loop will say, after for loop: i = 2 因此,在执行步骤3之前,您已经设置了i=2因此, for循环之后的最终console.log将显示, after for loop: i = 2

This occurs because of scope. 发生这种情况是由于范围。 Inside the EventListener , you have an anonymous function, because of this, you are no longer in the scope of li . EventListener内部,您具有匿名函数,因此,您不再在li的范围内。 However, you can refer to it with the this keyword. 但是,您可以使用this关键字来引用它。 See the alert that I've replaced in your code. 查看代码中我已替换的警报。

 (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> 

Another approach in addition to the answers of other posters is to use a local scope with function . 除了其他发布者的答案之外,另一种方法是使用具有function的局部范围。 In JavaScript function is the most reliable way of creating a new scope. 在JavaScript中, function是创建新范围的最可靠方法。 Taking the above example, 以上述示例为例,

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 have created a new scope that that will isolate the value of variable i . 我创建了一个新的作用域,它将隔离变量i的值。 If you're using ES6 you can use let keyword to do just the same thing. 如果您使用的是ES6,则可以使用let关键字执行相同的操作。 All you have to do is replace var with let . 您要做的就是用let替换var You can also use let in a for loop that will give you a whole new scope that is local to for loop. 您还可以在for循环中使用let ,这将为您提供for循环本地的全新作用域。

You need to refer to the particular li on which you want to attach the event 您需要参考要附加事件的特定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);
      } 
    }());

When click will be executed i will have value as 3 (in your case) so li[i] will be different. click将被执行时, i值为3(在您的情况下),因此li[i]会有所不同。 You can check the console of THIS to check value of i on click event 您可以检查THIS的控制台以检查click事件中i

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM