No Function Reassignment
ID |
javascript.no_func_assign |
Severity |
low |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
JavaScript |
Tags |
reliability, suspicious-assignment |
Description
Reports assignments to a binding declared by a function or function* declaration. Once function foo() {} runs, the statement foo = something; silently replaces the binding so subsequent calls to foo() no longer reach the declared body. Almost every occurrence is a typo (the author meant a different name) or a leftover from a refactor that should have removed the original declaration.
Property assignments such as foo.bar = …, destructuring targets, and assignments to other binding kinds (let / const / var / class / parameter / import) are out of scope — they are covered by sibling rules.
Rationale
-
A
functiondeclaration creates a binding hoisted to the top of the enclosing scope. Code anywhere in that scope can callfoo()and expect the declared body. Reassigningfooinvalidates that expectation but the original declaration stays visible to readers, which makes the bug very hard to spot. -
The reassignment is legal in non-strict mode (it throws in strict mode); silent failure is the worst kind.
// Bad
function format(value) { return String(value); }
// 100 lines later, in a refactor:
format = "default"; // typo — meant `defaultFormat`. format() now throws.
Remediation
If the binding really needs to change, declare it with let or const from the start so the intent is explicit. If the assignment is a typo, use a different identifier.
// Good
let format = (value) => String(value);
format = (value) => value.toUpperCase();