The Rest and Spread Operators (...)
Introduced in ES6 (ES2015), the three dots ... serve two closely related but distinct purposes in JavaScript depending on where they are used: the Rest parameter and the Spread syntax.
1. The Spread Syntax
The spread syntax "expands" an iterable (like an array, string, or object) into its individual elements. It is primarily used when all elements from an object or array need to be included in a new array or object.
Spreading Arrays
Copying an array:
const arr1 = [1, 2, 3];
const copy = [...arr1];
// copy is [1, 2, 3], but modifying copy won't affect arr1 (shallow copy)
Concatenating arrays:
const arr1 = [1, 2];
const arr2 = [3, 4];
const combined = [...arr1, ...arr2, 5, 6];
// [1, 2, 3, 4, 5, 6]
Passing arguments to functions:
Before ES6, we used Function.prototype.apply(). Spread makes this much cleaner.
const numbers = [9, 4, 7, 1];
const min = Math.min(...numbers); // expands to Math.min(9, 4, 7, 1)
console.log(min); // 1
Spreading Objects (ES2018)
You can also use the spread operator to copy and merge objects.
Copying an object:
const user = { name: "Alice", age: 25 };
const userClone = { ...user };
Merging objects: If there are conflicting keys, the last object spread overwrites the previous ones.
const defaults = { theme: "light", showSidebar: true };
const userSettings = { theme: "dark" };
const finalSettings = { ...defaults, ...userSettings };
// { theme: "dark", showSidebar: true }
2. The Rest Parameter
While spread expands an array into its elements, the rest parameter collects multiple elements and condenses them into a single array. It is heavily used in function declarations and destructuring.
Rest Parameters in Functions
The rest parameter allows a function to accept an indefinite number of arguments as an array.
function sum(...numbers) {
// 'numbers' is an array containing all passed arguments
return numbers.reduce((acc, curr) => acc + curr, 0);
}
console.log(sum(1, 2, 3)); // 6
console.log(sum(10, 20, 30, 40)); // 100
Rule: The rest parameter must always be the last argument in the function definition.
// Valid
function greet(greeting, ...names) {
names.forEach(name => console.log(`${greeting}, ${name}!`));
}
// Invalid: function greet(...names, greeting) { ... }
Rest in Array Destructuring
You can use the rest operator to extract remaining items of an array into a new array.
const [first, second, ...remaining] = [10, 20, 30, 40, 50];
console.log(first); // 10
console.log(remaining); // [30, 40, 50]
Rest in Object Destructuring (ES2018)
Similar to arrays, you can collect the remaining enumerable properties of an object.
const user = { id: 1, name: "Bob", role: "admin", active: true };
const { id, name, ...otherDetails } = user;
console.log(name); // "Bob"
console.log(otherDetails); // { role: "admin", active: true }
Key Differences Summary
| Feature | Operator | Purpose | Where is it used? |
| :--- | :--- | :--- | :--- |
| Spread | ... | Expands an iterable into individual elements. | Function calls (fn(...args)), Array literals ([...arr]), Object literals ({...obj}). |
| Rest | ... | Collects multiple elements into a single array/object. | Function definitions (function fn(x, ...y)), Destructuring assignments. |
Understanding both uses of ... is essential for writing clean, modern, and declarative JavaScript.