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 function declaration creates a binding hoisted to the top of the enclosing scope. Code anywhere in that scope can call foo() and expect the declared body. Reassigning foo invalidates 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();