← Home ← Codex ← DEBT
Browse by Category
+ added · updated 7d
← Back to glossary

Accidental Object Mutation Bugs

JavaScript ES2015 Intermediate
debt(d5/e3/b5/t7)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5). ESLint with mutation-detection plugins (e.g. eslint-plugin-immutable, eslint-plugin-no-mutation) can catch common patterns like .push(), .sort(), .splice() automatically, but catching all mutation patterns—especially indirect mutations through function calls or nested property changes—requires deeper analysis. Many mutation bugs only surface at runtime or during testing.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix confirms one-line replacements (spread syntax [...arr], {...obj}, structuredClone()) solve most cases. Refactoring direct state mutations to use immutable patterns is typically localized to a single function or component, not cross-cutting.

b5 Burden Structural debt — long-term weight of choosing wrong

Closest to 'persistent productivity tax' (b5). The term applies across web and CLI contexts. Preventing accidental mutation requires discipline in every array/object operation—developers must consistently choose immutable patterns (map/filter/slice over sort/splice/push), and React codebases especially bear this cost because state mutation silently breaks reactivity. This choice shapes coding patterns across multiple work streams but doesn't redefine the entire system architecture.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7). The canonical misconception ('const prevents object mutation') directly contradicts how const actually works in JavaScript and is a documented gotcha that most JS developers eventually learn. The trap is severe because const gives a false sense of safety—developers expect it to prevent mutation but it only prevents reassignment, leading to silent bugs. This contradicts similar immutability guarantees in other languages (e.g. Rust's const correctness).

About DEBT scoring →

TL;DR

Objects and arrays are passed by reference in JS — mutating a function parameter or array element mutates the original, causing subtle cross-component state bugs.

Explanation

JavaScript passes objects and arrays by reference. Mutating a function parameter mutates the caller's object. Common in: React state mutations (never mutate state directly), Redux reducers, array methods (sort(), splice(), reverse() mutate in place vs map(), filter(), slice() which return new arrays). Solutions: spread to clone ({...obj}), structuredClone() for deep clone, Object.freeze() to prevent mutation, immutable patterns. Mutation detection: Redux DevTools, React StrictMode double-invokes reducers to catch mutations.

Common Misconception

const prevents object mutation — const only prevents reassignment of the binding, not mutation of the object's properties.

Why It Matters

Accidental mutation causes shared state bugs where changing data in one component silently affects another — extremely hard to debug in large applications.

Common Mistakes

  • Sorting arrays in place without cloning: users.sort() mutates the original.
  • Mutating React state directly: state.items.push(item) — never re-renders.
  • Not knowing splice() mutates but slice() doesn't.

Code Examples

✗ Vulnerable
// React anti-pattern — direct state mutation:
const [items, setItems] = useState([]);
function addItem(item) {
    items.push(item); // Mutates state — React won't re-render
    setItems(items);
}
✓ Fixed
// Immutable patterns:
function addItem(item) {
    setItems(prev => [...prev, item]); // New array — React re-renders
}

// Sort without mutation:
const sorted = [...users].sort((a, b) => a.name.localeCompare(b.name));

// Deep clone:
const safeCopy = structuredClone(complexObject);

Added 22 Mar 2026
Edited 12 Jun 2026
Views 83
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 2 pings F 1 ping S 1 ping S 1 ping M 1 ping T 2 pings W 1 ping T 1 ping F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W
No pings yet today
No pings yesterday
Amazonbot 20 Perplexity 14 Google 8 Scrapy 7 ChatGPT 5 Unknown AI 3 Majestic 3 Ahrefs 3 Claude 2 Meta AI 1 Sogou 1 SEMrush 1
crawler 63 crawler_json 4 pre-tracking 1
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: Medium
⚡ Quick Fix
Use spread [...arr] or {...obj} for shallow clone. Use structuredClone() for deep clone. Prefer non-mutating array methods (map, filter, slice). Freeze objects with Object.freeze().
📦 Applies To
javascript ES2015 web cli
🔗 Prerequisites
🔍 Detection Hints
\.push\(|\.sort\(|\.splice\(
Auto-detectable: ✓ Yes eslint
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: Medium Context: Function Tests: Update

✓ schema.org compliant