Spread vs Rest Operators in JavaScript
Understanding the Power of `...` in JavaScript: Expanding vs Collecting Values
Spread vs Rest Operators in JavaScript
Same syntax, Different jobs.
If you've worked with modern JavaScript, you have probably seen ... (three dots) syntax everywhere.
At first if feels confusing. Sometimes it expands values, sometimes it collects them. That is because this same syntax is used for two different things.
Spread Operator --> expands values
Rest Operator --> collects values
Let's discuss it down in a simple way.
What is Spread Operator?
The spread operator is used to expand elements. Think of it like opening a box and laying everything out.
Example with Arrays
const nums = [1, 2, 3];
const newNums = [...nums, 4, 5];
console.log(newNums);
// [1, 2, 3, 4, 5]
...numsspreads the array valuesIt becomes
1, 2, 3
What is the Rest Operator?
The rest operator is used to collect multiple values into one. Think of it like putting things into a box.
Example with Function Parameters
function sum(...numbers) {
return numbers.reduce((acc, curr) => acc + curr, 0);
}
console.log(sum(1, 2, 3, 4))
// 10
...numberscollects all arguments into an arraynumbers = [1, 2, 3, 4]
Key Difference (Core idea)
| Spread | Rest |
|---|---|
| Expands values | Collects values |
| Used while sending data | Used while receiving data |
| Appears in function calls, arrays, objects | Appears in function parameters, destructuring |
Simple way to remember:
Spread = unpack
Rest = pack
Merge Arrays
const a = [1, 2]
const b = [3, 4]
const merged = [...a, ...b];
//Result
[1, 2, 3, 4]
Using Spread with Objects
Copy an Object
const user = {name: "John", age: 25};
const newUser = {...user};
Update Object Values
const user = {name: "John", age: 25};
const updatedUser = {
...user,
age: 26
};
here old values are copied then overridden.
Using Rest in Destructuring
Arrays
const name = [1, 2, 3, 4]
const [first, ...rest] = nums;
console.log(first); // 1
console.log(rest); // [2, 3, 4]
Objects
const user = {
name: "John",
age: 25,
city: "Delhi"
}
const {name, ...rest} = user;
console.log(name); // John
conole.log(rest); // { age: 25, city: "Delhi" }
Practical Use Cases
1. Avoid Mutating Data
const original = [1, 2, 3];
const updated = [...original, 4];
You keep the original safe.
2. Flexible Functions
function logAll(...args) {
console.log(args);
}
logAll(1, "hello", true);
Works with any number of inputs.
3. Combine Data Easily
const defaultSettings = { theme: "light" };
const userSettings = { fontSize: 16 };
const finalSettings = {
...defaultSettings,
...userSettings
};
One Important Detail (Edge Case)
const user = {
name: "John",
address: { city: "Delhi" }
};
const copy = { ...user };
copy.address.city = "Mumbai";
console.log(user.address.city);
// Mumbai 😬
Why?
Because nested objects are still shared by reference.
Fixing the Shallow Copy Problem (Deep Copy in JavaScript)
Using structuredClone() (Modern & Clean)
const user = {
name: "John",
address: { city: "Delhi" }
};
const deepCopy = structuredClone(user);
deepCopy.address.city = "Mumbai";
console.log(user.address.city);
// Delhi ✅