JavaScript Spread & Rest Operators: Complete Guide
What You'll Learn:
- ✅ Spread operator syntax and usage
- ✅ Rest parameters in functions
- ✅ Array spreading and cloning
- ✅ Object spreading and merging
- ✅ Copying vs referencing data
- ✅ Spread in function calls
- ✅ When to use spread vs alternatives
- ✅ Interview questions
What is the Spread Operator?
The spread operator (...) allows iterable objects (like arrays or strings) to be expanded in places where zero or more elements are expected. It's one of the most useful ES6 features, making code cleaner and enabling powerful operations on collections and objects.
Spread in Arrays
Array Spreading Basics
// Spread unpacks array elements
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
// Without spread: [[1,2,3], [4,5,6]]
const wrong = [arr1, arr2];
console.log(wrong); // [[1,2,3], [4,5,6]]
// With spread: [1, 2, 3, 4, 5, 6]
const combined = [...arr1, ...arr2];
...Spread unpacks array elements inline, useful for combining arrays and adding elements.
Cloning Arrays and Objects
Spread is a great way to create shallow copies of arrays and objects, avoiding unintended mutations.
Cloning with Spread
// Clone an array (shallow copy)
const original = [1, 2, 3];
const clone = [...original];
console.log(clone); // [1, 2, 3]
console.log(clone === original); // false (different arrays)
// Modifying clone doesn't affect original
clone[0] = 99;
console.log(original[0]); // 1 (unchanged)
...Spread creates shallow copies. For nested objects, you need deep cloning techniques.
Spread in Objects
Object Spreading
// Merge objects
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
const merged = { ...obj1, ...obj2 };
console.log(merged); // { a: 1, b: 2, c: 3, d: 4 }
// Override properties (last one wins)
const base = { x: 1, y: 2, z: 3 };
const override = { y: 20, z: 30 };
const result = { ...base, ...override };
...Object spread merges objects. Later properties override earlier ones with the same key.
Spread in Function Calls
Spread in Function Arguments
// Pass array elements as separate arguments
function sum(a, b, c) {
return a + b + c;
}
const nums = [1, 2, 3];
const result = sum(...nums); // Equivalent to sum(1, 2, 3)
console.log(result); // 6
// Math functions
...Spread in function calls unpacks array elements as individual arguments.
Rest Parameters vs Spread Operator
Rest parameters are the opposite of spread - they collect multiple arguments into an array. Both use ... but in different contexts.
Rest Parameters
// REST: Collect multiple arguments into array
function sum(...numbers) {
return numbers.reduce((a, b) => a + b, 0);
}
console.log(sum(1, 2, 3)); // 6
console.log(sum(5, 10, 15, 20)); // 50
console.log(sum()); // 0
// Rest with other parameters
...Rest parameters collect multiple arguments. Spread expands arrays. Both use ... but have opposite effects.
Real-World Examples
Practical Spread Usage
// 1. Combine arrays from multiple sources
const oldItems = [1, 2, 3];
const newItems = [4, 5];
const allItems = [...oldItems, ...newItems];
// 2. Create variations without mutation
const config = { timeout: 5000, retries: 3, debug: false };
const prodConfig = { ...config, debug: false };
const devConfig = { ...config, debug: true, timeout: 10000 };
...Spread is crucial for immutable programming, which prevents unintended side effects.
Spread vs Alternatives
When to Use Spread
// Array copying alternatives
const original = [1, 2, 3];
// Method 1: Spread (modern, clean)
const copy1 = [...original];
// Method 2: slice()
const copy2 = original.slice();
// Method 3: Array.from()
...Spread is the modern, preferred way for copying and merging. It's cleaner than older alternatives.
Common Pitfalls
Things to Watch For
// PITFALL 1: Shallow copy doesn't deep clone
const nested = { user: { name: "Alice" } };
const copy = { ...nested };
copy.user.name = "Bob";
console.log(nested.user.name); // "Bob" (affected!)
// PITFALL 2: Order matters in object spread
const base = { x: 1, y: 2 };
const override = { x: 10 };
const result1 = { ...base, ...override };
...Shallow copying, order sensitivity, and nested structures are common spread pitfalls.
Interview Q&A
Q: What's the difference between spread and rest?
A: Spread (...array) expands array into individual elements. Rest (...params) collects multiple arguments into an array. Spread is used in function calls or array/object literals. Rest is used in function parameters or destructuring.
Q: Why doesn't spread create a deep copy?
A: Spread creates a shallow copy - it copies the first level only. For nested objects/arrays, references are still shared. Deep copying requires recursion or libraries like lodash.deepClone().
Q: Can you use spread in loops?
A: Spread is for immediate expansion, not looping. For loops, use array methods like map(), filter(), or forEach(). However, you can use spread to unpack arrays into rest parameters.
Summary
- 🎯 Spread (...) expands arrays/objects inline
- 🎯 Rest (...) collects arguments into arrays
- 🎯 Great for copying and merging without mutation
- 🎯 Creates shallow copies only
- 🎯 Improves code readability vs concatenation
- 🎯 Works in arrays, objects, and function calls
- 🎯 Preferred modern alternative to slice/concat/Object.assign