2014-10-02 120 views
2

有人能向我解释为什么JSLint的抱怨“内循环功能”这个例子:循环内的JavaScript函数

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

第二个示例将我与回调绑定。第一个不是。在第一个例子中,你的所有i值都等于n。第二个将有0到n-1。 – mithunsatheesh 2014-10-02 03:44:53

+1

@mithunsatheesh - 再看一遍。第一个是IFFE,并执行相同的绑定。 – 2014-10-02 03:47:57

+0

这只是jsLint提供的不足警告。人们给予的警告比应得的更多。它可以警告你不应该做的事情,但它警告的事情不是问题,甚至是必须改变的东西。 – jfriend00 2014-10-02 03:52:01

回答

3

你的两个例子是不等价的。

首先,您正在创建一个匿名函数并在每个循环中调用它。

内部函数(click事件处理程序)很好 - 您正在分配一个新函数 - 但它是在此上下文中效率低下的匿名外部函数。在你的第二个例子中,外部函数被重构出循环,它只创建一次,而不是buttons.length次。

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稍后发生变化(在下一次迭代循环中),则iCopy不受影响。

这会像我们预期的那样工作,但现在的问题是JavaScript解释器将在每次循环迭代中创建捕获函数的实例。它必须这样做,因为它不知道函数对象是否会在其他地方被修改。由于函数是标准的JavaScript对象,因此它们可以具有任何其他对象的属性,这些对象可以在循环中更改。因此,通过在循环上下文中创建函数,会导致解释器创建多个函数实例,这可能会导致意外的行为和性能问题。为了解决这个问题,我们需要移动的功能圈外:

我本来希望在这里使用Array.prototype.forEach,这样

buttons.forEach(function(curButton) { 
    curButton.onclick = function(e) { 
     t.progressBars[t.current].update(curButton.getAttribute("data-value")); 
    }; 
}); 
+1

使用IIFE创建闭包是循环中的标准问题解决机制。我根本没有看到任何问题。如果你不需要闭包,代码可以被移动到一个外部定义的函数,所以它是一个函数调用,而不是一个IIFE,但是有一些权衡(不能访问父范围变量),额外的符号声明,代码不内联为了可读性等... – jfriend00 2014-10-02 03:54:40

+0

@ jfriend00同意。我只是指出了jsLint对代码的看法:-) – thefourtheye 2014-10-02 03:56:17