If you've worked with arrays, objects, and functions, you've probably seen the ... syntax in JavaScript.
For example:
const numbers = [1, 2, 3];
const copy = [...numbers];The same ... syntax can also be used in functions:
function add(...numbers) {
console.log(numbers);
}It looks the same, but it has two different purposes:
Spread → expands values.
Rest → collects values.
Understanding the difference is important because you'll see ... everywhere in modern JavaScript.
What is the Spread Operator?
The spread operator (...) expands the elements of an iterable or the properties of an object into another place.
In simple words:
Spread takes something that contains multiple values and spreads those values out.
For example:
const numbers = [1, 2, 3];
console.log(...numbers);Output:
1 2 3Instead of treating numbers as one array, ...numbers expands it into individual values.
Spread with Arrays
One of the most common uses of spread is combining arrays.
const fruits = ["Apple", "Banana"];
const vegetables = ["Carrot", "Potato"];
const food = [...fruits, ...vegetables];
console.log(food);Output:
["Apple", "Banana", "Carrot", "Potato"]Without spread, you might accidentally create a nested array:
const food = [fruits, vegetables];
console.log(food);which gives:
[
["Apple", "Banana"],
["Carrot", "Potato"]
]Spread lets us put their individual elements into the new array.
Copying an Array
Spread is also commonly used to create a shallow copy of an array.
const numbers = [10, 20, 30];
const copy = [...numbers];
console.log(copy);Output:
[10, 20, 30]Now copy is a different array:
copy.push(40);
console.log(numbers);
console.log(copy);Output:
[10, 20, 30]
[10, 20, 30, 40]The original array wasn't changed.
Remember: this is a shallow copy. If the array contains objects or other arrays, nested values are still shared.
Adding Elements with Spread
We can easily add elements while creating a new array.
const numbers = [2, 3, 4];
const newNumbers = [1, ...numbers, 5];
console.log(newNumbers);Output:
[1, 2, 3, 4, 5]This is very useful when creating updated versions of arrays without modifying the original.
Spread with Objects
The spread operator also works with objects.
const person = {
name: "John",
age: 25
};
const updatedPerson = {
...person,
city: "Delhi"
};
console.log(updatedPerson);Output:
{
name: "John",
age: 25,
city: "Delhi"
}Here, ...person copies the properties from person into the new object.
Copying an Object
We can create a shallow copy of an object using spread:
const person = {
name: "John",
age: 25
};
const copy = { ...person };Now copy is a separate object.
copy.age = 30;
console.log(person.age);
console.log(copy.age);Output:
25
30Again, this is a shallow copy, not a deep copy.
Updating Objects with Spread
Spread is extremely useful for creating an updated object.
const user = {
name: "John",
age: 20
};
const updatedUser = {
...user,
age: 21
};
console.log(updatedUser);Output:
{
name: "John",
age: 21
}Notice that the original object isn't modified.
This pattern is very common in modern JavaScript and frontend frameworks.
What is the Rest Operator?
Now let's look at the other use of ....
The rest operator collects multiple values into a single array or object.
In simple words:
Rest takes multiple values and collects them together.
For example:
function add(...numbers) {
console.log(numbers);
}
add(10, 20, 30, 40);Output:
[10, 20, 30, 40]Here, ...numbers collects all the arguments into an array.
Rest Parameters in Functions
Rest parameters are useful when we don't know how many arguments a function will receive.
function add(...numbers) {
let total = 0;
for (let number of numbers) {
total += number;
}
return total;
}
console.log(add(10, 20));
console.log(add(10, 20, 30, 40));Output:
30
100The function can accept any number of arguments.
Rest with Normal Parameters
Rest parameters can also be used together with regular parameters.
function greet(greeting, ...names) {
console.log(greeting);
console.log(names);
}
greet("Hello", "John", "Alex", "Sarah");Output:
Hello
["John", "Alex", "Sarah"]Here:
greeting → "Hello"
names → ["John", "Alex", "Sarah"]The rest parameter must be the last parameter.
This is invalid:
function test(...numbers, name) {
// ❌ Invalid
}Rest with Array Destructuring
We can also use rest when destructuring arrays.
const numbers = [10, 20, 30, 40, 50];
const [first, second, ...remaining] = numbers;
console.log(first);
console.log(second);
console.log(remaining);Output:
10
20
[30, 40, 50]Here, ...remaining collects everything left after the first two values.
Rest with Object Destructuring
The rest syntax also works with objects.
const person = {
name: "John",
age: 25,
city: "Delhi"
};
const { name, ...details } = person;
console.log(name);
console.log(details);Output:
John
{
age: 25,
city: "Delhi"
}The ...details part collects all remaining properties.
Spread vs Rest
This is the most important part to understand.
Both use:
...But their purpose depends on where they're used.
Spread | Rest |
|---|---|
Expands values | Collects values |
Used to unpack | Used to gather |
Common with arrays and objects | Common with function parameters and destructuring |
|
|
|
|
A simple trick:
Spread → Spread things out
Rest → Gather the rest together
A Practical Example
Imagine we're building a shopping cart.
const cart = ["Laptop", "Mouse"];
const newCart = [...cart, "Keyboard"];
console.log(newCart);Output:
["Laptop", "Mouse", "Keyboard"]Here, spread lets us create a new cart without modifying the original.
Now suppose we want a function that calculates the total of any number of prices:
function calculateTotal(...prices) {
return prices.reduce((total, price) => total + price, 0);
}
console.log(calculateTotal(1000, 500, 200));Output:
1700Here, rest collects all the arguments into the prices array.
So in the same application:
Spread → Expand existing data
Rest → Collect incoming dataConclusion
The ... syntax has two different jobs in JavaScript.
Spread expands values:
const numbers = [1, 2, 3];
const copy = [...numbers];Rest collects values:
function add(...numbers) {
// numbers is an array
}The easiest way to remember the difference is:
Spread = unpack
Rest = pack
You'll use these operators constantly in modern JavaScript, especially when working with arrays, objects, functions, destructuring, and modern frontend frameworks.