我一直在尝试使用for循环将click
个事件添加到一系列divs
。 divs
是动态创建和加载的。每个div都应该调用自己的回调函数。但似乎每个div都附加到最终事件监听器并调用最终事件监听器的回调函数。
以下是我的基本代码:
for(index=0; index<divs.length; index++) {
divs[index].addEventListener("click", function(){console.log(divs[index].getAttribute("id"));}, true); //capture click event
}
点击时,每个div只显示最终div的id。
答案 0 :(得分:8)
Phil's answer为您发布的特定代码(+1)提供了一个很好的解决方案,但没有解释原始代码的问题。
问题是事件处理程序闭包会在index
变量中获得持久引用,而不是在创建它们时的副本 。所以他们都看到了index
的最终价值(divs.length
)。例如,这段代码
for (index = 0; index < 4; ++index) {
setTimeout(function() {
console.log(index);
}, 100);
}
...超时时会记录“4”四次,而不是“0”,“1”,“2”和“3”。
要在您希望确保处理程序关闭特定值的一般情况下更正它,请使用为您生成事件处理函数的工厂函数,其中事件处理程序关闭您为工厂函数提供的参数而不是循环变量:
for(index=0; index<divs.length; index++) {
divs[index].addEventListener("click", createHandler(divs[index], true); //capture click event
}
function createHandler(div) {
return function(){
console.log(div.getAttribute("id"));
};
}
在那里,事件处理程序关闭div
,但不会改变。
闭包是JavaScript最强大的功能之一。一旦你理解它们是如何工作的(它们实际上比人们想象的要简单得多),你就可以使用它们来达到很好的效果。更多:Closures are not complicated
答案 1 :(得分:3)
这是因为你在事件处理程序中使用divs[index]
,在循环完成后,它被设置为最后一个元素。
请改用this
。此外,您可以使用一个事件处理程序,而不是创建一堆相同的闭包,例如
function logId(e) {
console.log(this.getAttribute("id"));
}
......并在你的循环中......
divs[index].addEventListener("click", logId, false);
请参阅https://developer.mozilla.org/en/DOM/element.addEventListener#Memory_issues
答案 2 :(得分:2)
您可以使用@phil指出的this
关键字。
但是,要解释你的问题是什么,请考虑这个闭包:
for(index=0; index<divs.length; index++) {
(function(index){
divs[index].addEventListener("click", function(){
console.log(divs[index].getAttribute("id"));
}, true);
})(index);
}
现在,每个函数都获得了index
变量的副本。在您的代码中,它们都共享相同的变量;最后,index
将等于divs.length -1
,无论实际点击哪个div
。