Spread & Rest Mastery
While they share the same syntax (...), the Spread and Rest operators serve opposite purposes. One expandsdata into a context, while the other collectsdata into a structure.
The Spread Operator (Expansion)
Spread allows you to "explode" an array or object into a position where multiple elements or properties are expected. It is the modern, idiomatic replacement for Array.prototype.concatand Object.assign.
// 1. Array Spread (Expansion)
const base = [1, 2];
const combined = [0, ...base, 3]; // [0, 1, 2, 3]
// 2. Object Spread (Expansion)
const defaultSettings = { theme: 'light', zoom: 100 };
const userSettings = { ...defaultSettings, theme: 'dark' };
// 3. Merging (Later keys overwrite earlier ones)
const final = { ...defaultSettings, ...userSettings };The Shallow Copy Hazard
It is critical to understand that spread creates a shallow copy. While top-level primitives are copied by value, any nested objects or arrays are copied by reference. Modifying a nested object in a spread clone will leak mutations back to the original source.
// --- The Shallow Copy Hazard ---
const original = {
id: 1,
meta: { roles: ['admin'] }
};
// Spread creates a shallow clone
const clone = { ...original };
// ⌠WARNING: Nested objects share references!
clone.meta.roles.push('editor');
console.log(original.meta.roles); // ['admin', 'editor']
// The original was accidentally modified!The Immutability Pattern
In frameworks like React and Redux, state must never be mutated. Spread is the primary tool for creating new state objects that incorporate changes while preserving the rest of the tree.
// --- Immutable Update Pattern (React/Redux) ---
const state = {
user: { id: 1, name: 'Alice' },
posts: [
{ id: 101, title: 'Hello World' },
{ id: 102, title: 'ES6 Spread' }
]
};
// Updating a single post without mutating the state
const updatedState = {
...state,
posts: state.posts.map(post =>
post.id === 101 ? { ...post, title: 'Updated Title' } : post
)
};The Rest Parameter (Collection)
Rest parameters allow a function to accept an indefinite number of arguments as an array. Unlike the legacy argumentsobject, rest parameters are true arrays and work perfectly within arrow functions.
// --- Rest Parameter (Collection) ---
// Essential for dynamic argument handling
const logger = (level, ...messages) => {
// Arrow functions DON'T have an 'arguments' object.
// Rest is the modern solution.
console.log(`[${level}]:`, ...messages);
};
logger('DEBUG', 'Init process', { step: 1 }, 'Success');for loops for extreme data sets.Senior Architect's Checklist:
- ✅ Expansion: Use spread to clone and merge objects/arrays cleanly.
- ✅ Collection: Use rest parameters
(...args)instead of the legacyargumentsobject. - ⌠Mutation: Remember that nested objects are still references in a spread clone.
- ✅ Ordering: In object spread, the order matters—later keys override earlier ones.
- ✅ State: Always use spread for top-level state updates in functional programming patterns.