Spread & Rest Operators (...)
The ... operator has two roles: spread (expand) and rest (collect). Spread copies/merges arrays and objects. Rest collects remaining arguments. Both are essential for immutable state management.
Spread vs Rest
- Spread (expand) — ...array expands into individual elements: [1, ...arr, 5]
- Rest (collect) — ...rest collects remaining items: function(first, ...rest) { }
- Context determines role — In function params/destructuring = rest. Everywhere else = spread
- Shallow copy — Spread creates shallow copies: { ...obj } or [...arr]. Nested objects still share references!
- Merge objects — { ...defaults, ...overrides }. Later properties win on conflicts
- Insert/replace in arrays — [...arr.slice(0, 2), newItem, ...arr.slice(3)]
Spread & Rest Code
// Spread — expand arrays
const nums = [3, 5, 1, 8, 2];
console.log(Math.max(...nums)); // 8 (spreads as individual args)
const merged = [...[1, 2], ...[3, 4], 5];
console.log(merged); // [1, 2, 3, 4, 5]
// Spread — copy and update objects (immutable pattern)
const user = { name: "Alice", age: 25, role: "user" };
const admin = { ...user, role: "admin", level: 5 };
console.log(admin); // { name: "Alice", age: 25, role: "admin", level: 5 }
// Rest — collect remaining
function sum(first, ...rest) {
console.log("First:", first);
console.log("Rest:", rest);
return rest.reduce((acc, n) => acc + n, first);
}
console.log(sum(1, 2, 3, 4, 5)); // First: 1, Rest: [2,3,4,5], Sum: 15
// Immutable array update (insert at index)
const items = ["a", "b", "c", "d"];
const index = 2;
const newItems = [...items.slice(0, index), "NEW", ...items.slice(index + 1)];
console.log(newItems); // ["a", "b", "NEW", "d"]
// ⚠️ Shallow copy warning!
const original = { name: "Alice", address: { city: "Mumbai" } };
const copy = { ...original };
copy.address.city = "Delhi"; // also changes original!
console.log(original.address.city); // "Delhi" ← shared reference!
// Deep copy solution
const deepCopy = JSON.parse(JSON.stringify(original));
// Or: structuredClone(original) in modern browsersTip
Tip
Use the spread operator to create immutable updates: const updated = { ...original, name: 'New Name' }. For arrays: const newArr = [...arr, newItem]. This pattern is the foundation of React state management.
Same syntax (...) — spread expands, rest collects. Context decides.
Common Mistake
Warning
Rest parameters must be the last parameter in a function: function fn(a, ...rest, b) is invalid. Also, rest creates a real array, while the old 'arguments' object is array-like but not a real array.
Practice Task
Note
Spread/rest mastery: (1) Merge two objects with spread, with the second overriding shared keys. (2) Write a function that accepts any number of arguments using rest. (3) Clone a nested object and verify independence.
Quick Quiz
Key Takeaways
- Spread (expand) — ...array expands into individual elements: [1, ...arr, 5]
- Rest (collect) — ...rest collects remaining items: function(first, ...rest) { }
- Context determines role — In function params/destructuring = rest. Everywhere else = spread