2015-05-27 117 views
2

我目前正在使用JsHint,並且正在接收警告W083:「不要在循環中創建函數」。我從JsLint Error Explanations閱讀這篇文章,並理解你爲什麼不應該這樣做,這基本上歸結爲JavaScript的異乎尋常的本質以及變量被覆蓋的可能性。

但是,我還在這裏閱讀了其他一些帖子,雖然這是一種失禮,但它並不總是會因情況而導致錯誤。

我的情況,特別是JsHint抱怨的是一個for循環,它使用jQuery $(selector).each()函數。該函數將一個函數作爲參數。以下是我關心的代碼片段。不要擔心,因爲我真的只是用這個作爲一個例子其實際作用+

for (var i = 0; i < sections.length; i++) { 
    disableSectionState[sections[i].name] = {}; 

    $('.' + sections[i].name).each(function (index, element) { 
     var id = $(element).attr('id'); 
     disableSectionState[sections[i].name][id] = $(element).attr('disabled'); 
    }); 

    if (sections[i].isChecked) { 
     $('.' + sections[i].name).attr('disabled', 'disabled'); 
    } 
} 

本質上來說,這僅僅是一個嵌套的for-each中的for循環,這樣循環我不認爲這會太危險,但我顯然不熟悉js中的所有怪癖。 截至目前,所有的東西都可以正常使用這個函數,但我想問問社區有關使用jQuery的循環中每個函數的危險。

爲了防止這被標記爲愚蠢我沒有看到this這個問題,但唯一的答案沒有涉及到任何細節或解釋任何東西,並根據評論它看起來像一個XY問題無論如何。我對更感興趣,爲什麼這是當它的核心是它本質上是一個嵌套循環。

這個函數在循環之外被提取和命名真的是更安全嗎?如果我將循環計數器複製到匿名函數範圍內的變量,是否可以消除此設計的潛在危險?該函數是否完全異步執行在主for循環之外?

+如果您確實感興趣:此代碼用於確定在啓用某些選項時是否在頁面加載時禁用某些字段。

回答

8

問題是沒有在循環中使用jQuery的each,它重複聲明一個函數。這可能會導致一些奇怪的關閉問題(該函數在循環計數器的引用上關閉,該引用仍然得到更新並且可能會更改),並且對不太聰明的虛擬機可能是一個不平凡的性能問題。

所有JSHint要求你改變的是:

function doStuff(index, element) { 
    var id = $(element).attr('id'); 
    disableSectionState[sections[i].name][id] = $(element).attr('disabled'); 
} 

for (var i = 0; i < sections.length; i++) { 
    disableSectionState[sections[i].name] = {}; 

    $('.' + sections[i].name).each(doStuff); 

    if (sections[i].isChecked) { 
    $('.' + sections[i].name).attr('disabled', 'disabled'); 
    } 
} 

最危險的到來,當你調用從一個循環內並關閉了循環計數器異步的東西。舉個例子來說:

for (var i = 0; i < urls.length; ++i) { 
    $.ajax(urls[i], {success: function() { 
    console.log(urls[i]); 
    }); 
} 

你可能認爲它會記錄每個URL的請求成功,但因爲i可能打length任何請求都來自於服務器返回之前,你就更有可能看到最後URL重複。如果你仔細考慮它是有道理的,但如果你沒有密切關注閉包或者有更復雜的回調,這可能是一個微妙的錯誤。

不聲明功能,您明確綁定或通過循環計數器,其他變量之間的循環部隊內,並防止這樣的事情意外此起彼伏。

在一些比較幼稚的實現,該機器也確實創造了循環的​​每次迭代功能的關閉範圍,以避免與內環路改變變量任何潛在的怪事。這可能會導致很多不必要的作用域,這會影響性能和內存。

+0

感謝您的見解!聽起來像我應該改變它,以防止未來的問題,並有可能提高性能。由於我需要內部函數的循環計數器,聽起來像我應該滾動一個單獨的函數來處理'$ .each'循環,並單獨保存變量以防止覆蓋。 – JNYRanger

+0

如果你使用類編寫JS,我喜歡只提供方法作爲我的事件回調。它可以讓你利用JS的靈活性,但也提供了一個很好的單元來測試。你可以使用'bind',但總是會創建一個新的函數或範圍,所以它會保證一些開銷。 – ssube

0

JSHint是一個非常基於觀點的語法檢查器。這就像決定在論文MLA或APA上進行哪種類型的引文一樣。如果你跟一個一起去,你只是遵循他們的規則,因爲大多數情況下,它是「正確的」,但它從來都不是錯誤的。 JSHint也說要始終使用===,但可能會有使用==的情況。

您可以遵循的規則或與下列

// Code here will be linted with JSHint. 
/* jshint ignore:start */ 
// Code here will be ignored by JSHint. 
/* jshint ignore:end */ 

如果你要使用JSHint不理會他們,我也只是遵照執行。它傾向於保持代碼更一致,當你開始嘗試解決一個警告或錯誤時,它往往開始創建更多

是否真的是更安全的提取此功能並在循環外命名?

  • 實際上,是的。一般情況下,可能不是。

如果我複製循環計數器在匿名函數的範圍變化,是否會消除這種設計的潛在危險?

是該功能主要用於循環之外執行的完全異步?

  • 很確定它是。