[英]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
循环结束后i
的值等于len
? 让我们用一个简单的例子来使您了解情况。
var len = 2;
for(var i=0; i<len; i++; {
//Do anything here
}
console.log("after for loop: i = " + i);
让我们来看一下迭代。
i = 0
,匹配条件i<len
,条件继续执行代码块,然后执行i++
,使i=1
; i = 1
,匹配条件i<len
,条件执行代码块,然后执行i++
,这使i=2
; 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.