循环内的 JavaScript 函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26154150/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JavaScript Function inside the loop
提问by spirytus
Can someone explain to me why JSLint complains about "Function inside the loop" with this example:
有人可以用这个例子向我解释为什么 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);
}
But dosen't when I change it to:
但是当我将其更改为:
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);
}
I don't quite understand as it seems that with each loop iteration new function object has to be returned, even though it happens inside of makeHandler()
function. Why the second example is ok with JS linters?
我不太明白,因为似乎每次循环迭代都必须返回新的函数对象,即使它发生在makeHandler()
函数内部。为什么第二个例子适用于 JS linters?
回答by thefourtheye
Quoting from linterrors,
引用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)); }
What we have now captures the value of
i
at each iteration of the loop. This happens because JavaScript passes arguments to functions by value. This means thatiCopy
within the capturing function is not related to i in any way (except for the fact that they happen to have the same value at that point in time). Ifi
changes later (which it does - on the next iteration of the loop) theniCopy
is not affected.This will work as we expect it to but the problem now is that the JavaScript interpreter will create an instance of the capturing function per loop iteration. It has to do this because it doesn't know if the function object will be modified elsewhere. Since functions are standard JavaScript objects, they can have properties like any other object, which could be changed in the loop. Thus by creating the function in the loop context, you cause the interpreter to create multiple function instances, which can cause unexpected behavior and performance problems. To fix the issue, we need to move the function out of the loop:
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 对象,因此它们可以像任何其他对象一样具有可以在循环中更改的属性。因此,通过在循环上下文中创建函数,您会导致解释器创建多个函数实例,这可能会导致意外行为和性能问题。为了解决这个问题,我们需要将函数移出循环:
I would have liked to use Array.prototype.forEach
here, like this
我本来想Array.prototype.forEach
在这里使用,像这样
buttons.forEach(function(curButton) {
curButton.onclick = function(e) {
t.progressBars[t.current].update(curButton.getAttribute("data-value"));
};
});
回答by Hamish
Your two examples are not equivalent.
你的两个例子是不等价的。
In the first, you are creating an anonymous function and calling it on every loop.
首先,您正在创建一个匿名函数并在每个循环中调用它。
The inner function (the click event handler) is fine - you're assigning a new function - but it's the anonymous outer function that is inefficient in this context. In your second example the outer function is refactored out of the loop where is it only created once, instead of buttons.length
times.
内部函数(单击事件处理程序)很好 - 您正在分配一个新函数 - 但匿名外部函数在这种情况下效率低下。在你的第二个例子中,外部函数被重构出循环,它只创建一次,而不是buttons.length
多次。