no-loop-func
Запрещает объявления функций, содержащие небезопасные ссылки внутри циклов
Функции, объявленные внутри циклов, часто приводят к ошибкам из-за того, как функция создает замыкание вокруг цикла. Например:
for (var i = 0; i < 10; i++) {
funcs[i] = function() {
return i;
};
}
В этом случае можно ожидать, что каждая функция, созданная внутри цикла, будет возвращать свое число. На самом деле каждая функция возвращает 10, поскольку это было последнее значение i в области видимости.
let или const помогают решить эту проблему.
for (let i = 0; i < 10; i++) {
funcs[i] = function() {
return i;
};
}
В этом случае каждая функция, созданная внутри цикла, возвращает свое число, как и ожидалось.
Подробное описание правила
Эта ошибка указывает на фрагмент кода, который может работать не так, как ожидается, а также может свидетельствовать о неверном понимании принципов работы языка. Код может выполняться без проблем, даже если вы не исправите эту ошибку, но в некоторых ситуациях его поведение может быть неожиданным.
Это правило запрещает функции внутри циклов, содержащие небезопасные ссылки (например, на изменяемые переменные из внешней области видимости). Правило игнорирует немедленно вызываемые функциональные выражения (IIFE), но не асинхронные функции и функции-генераторы.
Примеры неправильного кода для этого правила:
/*eslint no-loop-func: "error"*/
var i = 0;
while(i < 5) {
var a = ;
a();
i++;
}
var i = 0;
do {
;
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();
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();
}
foo = 100;
var arr = [];
for (var i = 0; i < 5; i++) {
arr.push((f => f)());
}
for (var i = 0; i < 5; i++) {
arr.push((() => {
return ;
})());
}
for (var i = 0; i < 5; i++) {
()();
}
Примеры правильного кода для этого правила:
/*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();
}
for (const i of foo) {
var a = function() { return i; }; // OK, all references are referring to block scoped variables in the loop.
a();
}
for (using i of foo) {
var a = function() { return i; }; // OK, all references are referring to block scoped variables in the loop.
a();
}
for (var i=10; i; i--) {
const foo = getsomething(i);
var a = function() { return foo; }; // OK, all references are referring to block scoped variables in the loop.
a();
}
for (var i=10; i; i--) {
using foo = getsomething(i);
var a = function() { return foo; }; // OK, all references are referring to block scoped variables in the loop.
a();
}
for (var i=10; i; i--) {
await using foo = getsomething(i);
var a = function() { return foo; }; // 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)();
})());
}
Это правило также поддерживает синтаксис типов TypeScript.
Примеры правильного кода TypeScript для этого правила:
/*eslint no-loop-func: "error"*/
type MyType = 1;
let someArray: MyType[] = [];
for (let i = 0; i < 10; i += 1) {
someArray = someArray.filter((item: MyType) => !!item);
}
Параметры
У этого правила нет параметров.
Известные ограничения
Правило не может определить, вызывается ли экземпляр функции немедленно и затем отбрасывается или, возможно, сохраняется для последующего использования.
const foo = [1, 2, 3, 4];
var i = 0;
while(foo.some(e => e > i)){
i += 1;
}
Здесь метод some сразу же выполняет функцию обратного вызова для каждого элемента массива, а затем отбрасывает экземпляр функции. Функция не сохраняется и не используется повторно за пределами итерации цикла. Поэтому код будет работать как задумано.
В таких случаях можно использовать комментарии eslint-disable.
Версия
Это правило добавлено в ESLint v0.0.9.
Ресурсы
© OpenJS Foundation and other contributors
Licensed under the MIT License.
https://eslint.org/docs/latest/rules/no-loop-func