版本

no-loop-func

不允許在迴圈語句內包含不安全參考的函式宣告

在迴圈中編寫函式往往會因為函式圍繞迴圈建立閉包的方式而導致錯誤。例如

for (var i = 0; i < 10; i++) {
    funcs[i] = function() {
        return i;
    };
}

在這種情況下,您會期望迴圈中建立的每個函式都返回不同的數字。但實際上,每個函式都返回 10,因為那是範圍中 i 的最後一個值。

letconst 減輕了這個問題。

for (let i = 0; i < 10; i++) {
    funcs[i] = function() {
        return i;
    };
}

在這種情況下,迴圈中建立的每個函式都會如預期返回不同的數字。

規則詳細資訊

提出此錯誤是為了突顯一段可能無法如您預期運作的程式碼,並且也可能表示對語言運作方式的誤解。如果您不修正此錯誤,您的程式碼可能會沒有任何問題地執行,但在某些情況下,它可能會出現意想不到的行為。

此規則不允許迴圈內的任何函式包含不安全的參考(例如,來自外部範圍的修改變數)。此規則忽略 IIFE,但不忽略 async 或 generator 函式。

此規則的不正確程式碼範例

在 Playground 中開啟
/*eslint no-loop-func: "error"*/

var i = 0;
while(i < 5) {
    var a = function() { return i; };
    a();

    i++;
}

var i = 0;
do {
    function a() { return i; };
    a();

    i++
} while (i < 5);

let foo = 0;
for (let i = 0; i < 10; ++i) {
    //Bad, `foo` is not in the loop-block's scope and `foo` is modified in/after the loop
    setTimeout(() => console.log(foo));
    foo += 1;
}

for (let i = 0; i < 10; ++i) {
    //Bad, `foo` is not in the loop-block's scope and `foo` is modified in/after the loop
    setTimeout(() => console.log(foo));
}
foo = 100;

var arr = [];

for (var i = 0; i < 5; i++) {
    arr.push((f => f)(() => i));
}

for (var i = 0; i < 5; i++) {
    arr.push((() => {
        return () => i;
    })());
}

for (var i = 0; i < 5; i++) {
    (function fun () {
        if (arr.includes(fun)) return i;
        else arr.push(fun);
    })();
}

此規則的正確程式碼範例

在 Playground 中開啟
/*eslint no-loop-func: "error"*/

var a = function() {};

for (var i=10; i; i--) {
    a();
}

for (var i=10; i; i--) {
    var a = function() {}; // OK, no references to variables in the outer scopes.
    a();
}

for (let i=10; i; i--) {
    var a = function() { return i; }; // OK, all references are referring to block scoped variables in the loop.
    a();
}

var foo = 100;
for (let i=10; i; i--) {
    var a = function() { return foo; }; // OK, all references are referring to never modified variables.
    a();
}
//... no modifications of foo after this loop ...

var arr = [];

for (var i=10; i; i--) {
    (function() { return i; })();
}

for (var i = 0; i < 5; i++) {
    arr.push((f => f)((() => i)()));
}

for (var i = 0; i < 5; i++) {
    arr.push((() => {
        return (() => i)();
    })());
}

已知限制

該規則無法識別函式實例是否只是立即調用然後丟棄,或者可能儲存以供稍後使用。

const foo = [1, 2, 3, 4];
var i = 0;

while(foo.some(e => e > i)){
    i += 1;
}

在這裡,some 方法會立即為陣列中的每個元素執行回呼函式,然後丟棄函式實例。該函式不會在迴圈迭代範圍之外儲存或重複使用。因此,這將按預期運作。

eslint-disable 註解可以用於這種情況。

版本

此規則在 ESLint v0.0.9 中引入。

資源

變更語言