The spread operator ('...') expands an iterable or object into individual elements. It is the idiomatic way professional JS code copies arrays/objects, merges data, and passes variable-length arguments.
1Spread Operator | JavaScript Tutorial - In-Depth Guide Part 1
The spread operator expands an array's elements in place, most commonly used to create a shallow copy without mutating the original.
const original = [1, 2, 3];
const copy = [...original];Array Copying
2Spread Operator | JavaScript Tutorial - In-Depth Guide Part 2
Spread also works on objects, producing a shallow copy that merges properties from left to right — later keys overwrite earlier ones.
const defaults = { theme: 'light', size: 'md' };
const final = { ...defaults, theme: 'dark' };Object Merging
3Spread Operator | JavaScript Tutorial - In-Depth Guide Part 3
Spread is 'shallow' — nested objects or arrays inside the copy are still shared references with the original.
const a = { user: { name: 'Al' } };
const b = { ...a };
b.user.name = 'Bo'; // a.user.name is 'Bo' too!Shallow Copy Trap
4Spread Operator | JavaScript Tutorial - In-Depth Guide Part 4
Spread can expand an array directly into a function call's argument list, replacing the older 'Function.prototype.apply'.
const numbers = [4, 9, 1];
Math.max(...numbers); // 9Spread into Calls
5Spread Operator | JavaScript Tutorial - In-Depth Guide Part 5
Combining spread with destructuring is the standard pattern for 'take these fields out, keep the rest' — common when omitting a property before sending data to an API.
const { password, ...safeUser } = fullUser;
// safeUser has everything except passwordOmit a Field
6Step-by-Step Breakdown
The spread operator expands an array's elements in place, most commonly used to create a shallow copy without mutating the original.
Spread also works on objects, producing a shallow copy that merges properties from left to right — later keys overwrite earlier ones.
Checkpoint: When you spread two objects with the same key, { ...a, ...b }, which value wins?
- →a's value, because it appears first
- →b's value, because it appears last
Spread is 'shallow' — nested objects or arrays inside the copy are still shared references with the original.
Checkpoint: If an object has a nested object property, does spreading the outer object also deep-copy the nested one?
- →Yes, spread copies every level
- →No, the nested object reference is shared
Spread can expand an array directly into a function call's argument list, replacing the older 'Function.prototype.apply'.
Combining spread with destructuring is the standard pattern for 'take these fields out, keep the rest' — common when omitting a property before sending data to an API.
Next, we'll explore 'Rest Parameters'.
Level Up 🚀
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1Immutable Prop Updates via Spread Keep Focus and ARIA State in Sync
Frameworks that track accessible state (focus rings, aria-expanded) via re-renders depend on new object references from spread-based updates; mutating state directly can leave the accessibility tree out of sync with what is visually rendered.
SEO Implications
- 1
Overusing Spread in Hot Paths Can Regress Interaction to Next Paint
Because spreading large arrays/objects allocates new memory every call, doing it inside frequently-firing handlers (scroll, input) rather than at meaningful state-change boundaries can add measurable input latency on lower-end devices.
Best Practices
Use Spread for Immutable State Updates
Frameworks like React rely on reference equality to detect changes; spreading into a new object/array (`{ ...state, count }`) instead of mutating in place is what makes re-renders trigger correctly.
Reach for `structuredClone()` When You Need a True Deep Copy
Because spread is shallow, nested mutable data needs either structuredClone(), a deep-clone utility, or a state management library rather than spread alone.
Frequent Bugs
A component spreads state to "copy" it, mutates a nested object on the copy, and the original state changes too, causing missed re-renders or shared corrupted data.
Spread only copies one level deep. Either spread each nested level explicitly (`{ ...state, user: { ...state.user, name } }`) or use structuredClone() / an immutability library for deep updates.
Spreading a very large array inside a hot loop (e.g. `[...arr, item]` on every iteration) causes O(n²) performance because each spread copies the whole array.
Build the array once with push() outside performance-critical loops, or batch updates, reserving spread-based immutable updates for less frequent, user-triggered state changes.
Real-World Examples
Merging Default Options with User Overrides
A configurable UI component needed to accept partial configuration from the caller while falling back to sensible defaults.
const defaultOptions = { theme: 'light', animate: true };
function createWidget(userOptions = {}) {
return { ...defaultOptions, ...userOptions };
}