no-loop-func

禁止在循环语句中包含不安全引用的函数声明

由于函数在循环周围创建闭包的方式,在循环中编写函数往往会导致错误。例如:

¥Writing functions within loops tends to result in errors due to the way the function creates a closure around the loop. For example:

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

在这种情况下,你会期望在循环中创建的每个函数都返回不同的数字。实际上,每个函数都返回 10,因为这是作用域中 i 的最后一个值。

¥In this case, you would expect each function created within the loop to return a different number. In reality, each function returns 10, because that was the last value of i in the scope.

letconst 缓解了这个问题。

¥let or const mitigate this problem.

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

在这种情况下,循环中创建的每个函数都按预期返回不同的数字。

¥In this case, each function created within the loop returns a different number as expected.

规则详情

¥Rule Details

引发此错误是为了高亮一段可能无法按预期工作的代码,并且还可能表明对该语言的工作方式存在误解。如果你不修复此错误,你的代码可能会毫无问题地运行,但在某些情况下,它可能会出现意外行为。

¥This error is raised to highlight a piece of code that may not work as you expect it to and could also indicate a misunderstanding of how the language works. Your code may run without any problems if you do not fix this error, but in some situations it could behave unexpectedly.

此规则不允许循环中包含不安全引用的任何函数(例如,从外部范围修改变量)。此规则忽略 IIFE,但不忽略异步或生成器函数。

¥This rule disallows any function within a loop that contains unsafe references (e.g. to modified variables from the outer scope). This rule ignores IIFEs but not async or generator functions.

此规则的错误代码示例:

¥Examples of incorrect code for this rule:

在线运行
/*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);
    })();
}

此规则的正确代码示例:

¥Examples of correct code for this rule:

在线运行
/*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)();
    })());
}

已知限制

¥Known Limitations

规则无法识别函数实例是立即调用然后丢弃,还是可能存储以供以后使用。

¥The rule cannot identify whether the function instance is just immediately invoked and then discarded, or possibly stored for later use.

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

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

这里 some 方法立即为数组中的每个元素执行回调函数,然后丢弃函数实例。函数不会在循环迭代范围之外存储或重用。因此,这将按预期工作。

¥Here the some method immediately executes the callback function for each element in the array and then discards the function instance. The function is not stored or reused beyond the scope of the loop iteration. So, this will work as intended.

在这种情况下可以使用 eslint-disable 注释。

¥eslint-disable comments can be used in such cases.

版本

此规则是在 ESLint v0.0.9 中引入。

资源

ESLint 中文网
粤ICP备13048890号