Spread vs Rest Operators in JavaScript

In JavaScript, the three dots (...) are a bit of a shape-shifter. Depending on exactly where and how you use them, they act as either the Spread operator or the Rest operator.
Lets breakdown of how they work, the differences between them, and how you'll actually use them in the real world.
1. The Spread Operator: Expanding Values
The spread operator takes an iterable (like an array or a string) or an object and expands it into individual elements. Imagine opening a box and spilling its contents out onto a table.
Using Spread with Arrays
Spread is incredibly useful for combining, copying, or inserting arrays into other arrays.
const original = [1, 2, 3];
const copy = [...original];
const fruits = ['apple', 'banana'];
const veggies = ['carrot', 'potato'];
const groceries = [...fruits, ...veggies, 'milk'];
// Result: ['apple', 'banana', 'carrot', 'potato', 'milk']
Using Spread with Objects
You can also use spread to unpack the properties of one object into a new object. This is heavily used for cloning or updating objects without mutating the original.
const user = { name: "Rachit", role: "Admin" };
const updatedUser = { ...user, active: true };
// Result: { name: "Rachit", role: "Admin", active: true }
const demotedUser = { ...user, role: "User" };
// Result: { name: "Rachit", role: "User" }
2. The Rest Operator: Collecting Values
The rest operator looks exactly the same (...), but it does the exact opposite. It collects multiple individual elements and condenses them into a single array or object. Think of it as sweeping remaining items back into a box.
Using Rest in Function Parameters
When you don't know how many arguments a function will receive, the rest operator scoops up all provided arguments into a single array.
function calculateTotal(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(calculateTotal(10, 20, 5)); // Result: 35
Using Rest in Destructuring
You can use rest to pull out specific items from an array or object, and bundle the "rest" of the items into a new variable.
const scores = [98, 85, 92, 74, 88];
const [firstPlace, secondPlace, ...otherScores] = scores;
// firstPlace = 98
// secondPlace = 85
// otherScores = [92, 74, 88]
// Object Destructuring
const settings = { theme: "dark", notifications: true, volume: 80 };
const { theme, ...otherSettings } = settings;
// theme = "dark"
// otherSettings = { notifications: true, volume: 80 }
3. Spread vs. Rest: The Core Differences
Feature | Spread (...) | Rest (...) |
Primary Action | Expands iterables/objects into individual elements. | Collects individual elements into an array/object. |
Where it's used | In function calls, array literals, or object literals. | In function definitions (parameters) or destructuring. |
Analogy | Unpacking a suitcase. | Packing items into a suitcase. |
Position matters? | Can be used anywhere in the array/object literal. | Must be the last item in a parameter list or destructuring assignment. |
4. Real-World Usage Patterns
Here are a few scenarios where you will see these operators used daily in modern JavaScript codebases:
1. Passing Array Elements as Function Arguments (Spread) If a function expects a comma-separated list of arguments, but your data is in an array, spread fixes that instantly.
const temperatures = [72, 85, 60, 91, 88];
// Math.max expects Math.max(72, 85, ...) not Math.max([72, 85, ...])
const highest = Math.max(...temperatures); // 91
2. Immutable State Updates in React (Spread) In frameworks like React, you should never mutate state directly. Spread allows you to create a fresh copy with updated values.
setUserState(prevState => ({
...prevState,
email: "newemail@example.com"
}));
3. Filtering Out Object Properties (Rest)
If you need to remove a sensitive property (like a password) from an object before sending it to a client, rest destructuring is the cleanest way.
const userFromDB = { id: 1, name: "Parth", passwordHash: "12345abcd", isAdmin: true };
const { passwordHash, ...safeUser } = userFromDB;
console.log(safeUser); // { id: 1, name: "Parth", isAdmin: true }



