版本

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 中引入。

资源

更改语言