JavaScript Spread Operator Shallow Copy Fix
In this tutorial, you'll learn about JavaScript Spread Operator Shallow Copy Fix. We cover key concepts, practical examples, and best practices.
The Problem
The spread operator (...) creates a shallow copy of objects and arrays. Nested objects and arrays are copied by reference, not by value. Mutating a nested property in the copy also mutates the original, leading to unpredictable bugs.
Quick Fix
Step 1: Know that spread is shallow
const original = { a: 1, nested: { b: 2 } };
// Wrong — thinks this is a deep copy
const copy = { ...original };
copy.nested.b = 99;
console.log(original.nested.b); // 99 — mutated the original too!
Step 2: Deep clone with structuredClone
const original = { a: 1, nested: { b: 2 } };
// Right — use structuredClone for deep copy
const deepCopy = structuredClone(original);
deepCopy.nested.b = 99;
console.log(original.nested.b); // 2 — original is unchanged
Step 3: Shallow copy is fine for flat objects
const config = { host: 'localhost', port: 3000 };
const updated = { ...config, port: 4000 };
console.log(config.port); // 3000 — unchanged
console.log(updated.port); // 4000
Step 4: Merge objects with spread
const defaults = { theme: 'dark', lang: 'en' };
const userPrefs = { lang: 'fr' };
// Right — userPrefs overrides defaults
const settings = { ...defaults, ...userPrefs };
console.log(settings); // { theme: 'dark', lang: 'fr' }
Step 5: Array spread is also shallow
const matrix = [[1, 2], [3, 4]];
const copy = [...matrix];
// Wrong — mutates the original
copy[0][0] = 99;
console.log(matrix[0][0]); // 99
// Right — deep copy for nested arrays
const deepCopy = structuredClone(matrix);
deepCopy[0][0] = 42;
console.log(matrix[0][0]); // 99 (original changed earlier)
// Use structuredClone before mutation
Step 6: Spread in function calls
// Wrong — passing array elements manually
const numbers = [5, 10, 15];
console.log(Math.max(numbers[0], numbers[1], numbers[2]));
// Right — spread arrays in function calls
console.log(Math.max(...numbers)); // 15
// Combine with other arguments
console.log(Math.max(0, ...numbers, 20)); // 20
Prevention
- Use
structuredClonefor objects with nested data - Use
JSON.parse(JSON.stringify(obj))only for serializable data (loses functions, dates, undefined) - Keep objects flat when possible to avoid shallow copy confusion
- Use immutable update patterns with spread for top-level properties
- Consider libraries like Immer for complex immutable state
Common Mistakes with spread operator
- Using
foldlinstead offoldl'causing stack overflow on large lists - Forgetting
deriving (Show, Eq)on custom data types needed for debugging - Placing the wildcard pattern first in case expressions, making all subsequent patterns unreachable
These mistakes appear frequently in real-world JS code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro