参见英文答案 > JavaScript closure inside loops – simple practical example 43个
我正在尝试使用for循环向多个对象添加事件侦听器,但最终会使用针对同一对象的所有侦听器 – >最后一个.
如果我通过为每个实例定义boxa和boxb来手动添加侦听器,它就可以工作.我想这就是addEvent for-loop,它不像我希望的那样工作.也许我完全使用了错误的方法.
使用4个类=“容器”的示例
容器4上的触发按照预期的方式工作.
触发容器1,2,3触发容器4上的事件,但仅在触发器已被激活时触发.
// Function to run on click:
function makeItHappen(elem, elem2) {
var el = document.getElementById(elem);
el.style.backgroundColor = "red";
var el2 = document.getElementById(elem2);
el2.style.backgroundColor = "blue";
}
// Autoloading function to add the listeners:
var elem = document.getElementsByClassName("triggerClass");
for (var i = 0; i < elem.length; i += 2) {
var k = i + 1;
var boxa = elem[i].parentNode.id;
var boxb = elem[k].parentNode.id;
elem[i].addEventListener("click", function() {
makeItHappen(boxa, boxb);
}, false);
elem[k].addEventListener("click", function() {
makeItHappen(boxb, boxa);
}, false);
}
<div class="container">
<div class="one" id="box1">
<p class="triggerClass">some text</p>
</div>
<div class="two" id="box2">
<p class="triggerClass">some text</p>
</div>
</div>
<div class="container">
<div class="one" id="box3">
<p class="triggerClass">some text</p>
</div>
<div class="two" id="box4">
<p class="triggerClass">some text</p>
</div>
</div>
解决方法:
瓶盖! :d
此固定代码按预期工作:
for (var i = 0; i < elem.length; i += 2) {
(function () {
var k = i + 1;
var boxa = elem[i].parentNode.id;
var boxb = elem[k].parentNode.id;
elem[i].addEventListener("click", function() { makeItHappen(boxa,boxb); }, false);
elem[k].addEventListener("click", function() { makeItHappen(boxb,boxa); }, false);
}()); // immediate invocation
}
为什么要修复它?
for(var i=0; i < elem.length; i+=2){
var k = i + 1;
var boxa = elem[i].parentNode.id;
var boxb = elem[k].parentNode.id;
elem[i].addEventListener("click", function(){makeItHappen(boxa,boxb);}, false);
elem[k].addEventListener("click", function(){makeItHappen(boxb,boxa);}, false);
}
实际上是非严格的JavaScript.它的解释如下:
var i, k, boxa, boxb;
for(i=0; i < elem.length; i+=2){
k = i + 1;
boxa = elem[i].parentNode.id;
boxb = elem[k].parentNode.id;
elem[i].addEventListener("click", function(){makeItHappen(boxa,boxb);}, false);
elem[k].addEventListener("click", function(){makeItHappen(boxb,boxa);}, false);
}
由于variable hoisting,var声明被移动到范围的顶部.由于JavaScript没有块范围(for,if,while等),因此它们被移动到函数的顶部.更新:从ES6开始,您可以使用let
获取块范围变量.
当代码运行时会发生以下情况:在for循环中添加单击回调并指定boxa,但在下一次迭代中它的值会被覆盖.当click事件触发回调运行时,boxa的值始终是列表中的最后一个元素.
使用闭包(关闭boxa,boxb等的值)将值绑定到单击处理程序的范围.
像JSLint或JSHint这样的代码分析工具将能够捕获这样的可疑代码.如果您正在编写大量代码,那么花些时间学习如何使用这些工具是值得的.有些IDE内置了它们.