Function Declared In Loop
ID |
javascript.no_loop_func |
Severity |
low |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Efficiency |
Language |
JavaScript |
Tags |
closures, efficiency, loops |
Description
Reports function literals (function expressions, arrow functions, named function declarations, async / generator forms) declared inside the body of a loop. Each iteration creates a fresh function, capturing the iteration’s locals; depending on the binding kind (var vs. let/const) the closure sees a stale or fresh value, and the per-iteration allocation cost compounds inside hot loops.
Rationale
// Bad — every iteration produces a new closure capturing `i`.
function bad(items) {
for (let i = 0; i < items.length; i++) {
const handler = () => items[i];
register(handler);
}
}
The closure-over-loop-variable hazard is the more famous bug: with var, every iteration’s closure ends up reading the same final value of the counter; with let it’s per-iteration but every callback gets a different one. Either way, the surprises usually outweigh the convenience.
Remediation
Hoist the function out of the loop, or pass per-iteration state explicitly:
// Good — function defined once, parameterised per iteration.
function ok(items) {
const handler = (i) => items[i];
for (let i = 0; i < items.length; i++) {
register(handler.bind(null, i));
}
}