有人可以向我解释为什么JSLint在这个例子中抱怨“循环中的函数”:
for (var i = 0; i < buttons.length; i++) {
(function(i) {
buttons[i].onclick = function(e) {
t.progressBars[t.current].update(buttons[i].getAttribute("data-value"));
}
})(i);
}
但是当我把它改为:
时function makeHandler(i)
{
return function() {
t.progressBars[t.current].update(buttons[i].getAttribute("data-value"));
}
}
for (var i = 0; i < buttons.length; i++) {
buttons[i].onclick = makeHandler(i);
}
我不太明白,因为似乎每次循环迭代都必须返回新的函数对象,即使它发生在makeHandler()
函数内部。为什么JS linters的第二个例子没问题?
答案 0 :(得分:5)
引自linterrors,
var elems = document.getElementsByClassName("myClass"), i; for (i = 0; i < elems.length; i++) { (function (iCopy) { "use strict"; elems[i].addEventListener("click", function () { this.innerHTML = iCopy; }); }(i)); }
我们现在在循环的每次迭代中捕获
i
的值。发生这种情况是因为JavaScript通过值将参数传递给函数。这意味着捕获函数中的iCopy
以任何方式与i无关(除非它们恰好在该时间点具有相同的值)。如果i
稍后更改(它会在下一次循环迭代中更改),则iCopy
不会受到影响。这将按照我们的预期工作,但现在的问题是JavaScript解释器将为每个循环迭代创建捕获函数的实例。它必须这样做,因为它不知道函数对象是否会在别处修改。由于函数是标准JavaScript对象,因此它们可以具有与任何其他对象相同的属性,这些属性可以在循环中更改。因此,通过在循环上下文中创建函数,可以使解释器创建多个函数实例,这可能会导致意外行为和性能问题。要解决这个问题,我们需要将该函数移出循环:
我希望在这里使用Array.prototype.forEach
,就像这样
buttons.forEach(function(curButton) {
curButton.onclick = function(e) {
t.progressBars[t.current].update(curButton.getAttribute("data-value"));
};
});
答案 1 :(得分:4)
你的两个例子并不等同。
在第一个中,您将创建一个匿名函数并在每个循环中调用它。
内部函数(click事件处理程序)很好 - 你正在分配一个新函数 - 但它是匿名外部函数,在这种情况下是低效的。在你的第二个例子中,外部函数被重构出来,它只创建一次,而不是buttons.length
次。