2014-10-02 73 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