Difference between spread and rest
The main difference in one sentence: spread unpacks elements (it expands an array or an object), while rest gathers elements (it packs the remainder into an array or an object). They are written identically, as three dots, so they are told apart by their position in the code rather than by their appearance.
Theory
TL;DR
- Spread expands a structure:
[...arr],{...obj},fn(...args). - Rest packs the remainder:
function fn(...args),[a, ...rest],{ a, ...rest }. - Spread lives in a call or creation context, rest in a declaration or destructuring context.
- The result of spread is separate elements; the result of rest is a new array or object.
...is not an operator of the language on its own, it is part of the destructuring and call syntax.- Both perform a shallow copy.
Quick example
function logFirstAndRest(first, ...rest) { // rest gathers
console.log('First:', first);
console.log('Others:', rest);
}
const numbers = [10, 20, 30, 40];
logFirstAndRest(...numbers); // spread expands
// What happens:
// logFirstAndRest(10, 20, 30, 40);
// first = 10
// rest = [20, 30, 40]Spread, unpacking data
Used when a structure (an array or an object) has to be expanded into separate elements.
Array example:
const arr = [1, 2, 3];
console.log(...arr); // 1 2 3Copying and merging:
const a = [1, 2];
const b = [3, 4];
const merged = [...a, ...b];
console.log(merged); // [1, 2, 3, 4]Object example:
const user = { name: 'Alex', age: 25 };
const newUser = { ...user, city: 'Paris' };
console.log(newUser); // { name: 'Alex', age: 25, city: 'Paris' }Function call example:
function sum(a, b, c) {
return a + b + c;
}
const nums = [1, 2, 3];
console.log(sum(...nums)); // 6One rule: spread opens a structure up.
Rest, gathering data
Used when several elements have to be collected into one structure (an array or an object).
Function example:
function sum(...numbers) {
return numbers.reduce((a, b) => a + b, 0);
}
console.log(sum(1, 2, 3, 4)); // 10Here
...numbersgathers every argument into the array[1, 2, 3, 4].
Array destructuring example:
const [first, ...rest] = [1, 2, 3, 4];
console.log(first); // 1
console.log(rest); // [2, 3, 4]Object destructuring example:
const user = { name: 'Alex', age: 25, city: 'Paris' };
const { name, ...info } = user;
console.log(name); // Alex
console.log(info); // { age: 25, city: 'Paris' }One rule: rest collects the remainder.
Head to head comparison
| Criterion | Spread (...) | Rest (...) |
|---|---|---|
| Action | Unpacks values | Gathers values |
| Where it is used | In function calls, arrays, objects | In function parameters and destructuring |
| Result | Separate elements | A new array or object |
| Array example | [...arr] gives 1, 2, 3 | [a, ...rest] gives rest = [2, 3] |
| Object example | {...obj} | { a, ...rest } |
| Function example | sum(...nums) | function sum(...nums) |
When the two meet
The difference is clearest where both appear in the same piece of code.
function logFirstAndRest(first, ...rest) {
console.log('First:', first);
console.log('Others:', rest);
}
const numbers = [10, 20, 30, 40];
logFirstAndRest(...numbers);
// Decoded: logFirstAndRest(10, 20, 30, 40);
// first = 10
// rest = [20, 30, 40]Spread expands numbers at the moment of the call, and rest gathers the arguments once inside the function. A simple mnemonic: spread means "expand", rest means "collect".
Common mistakes
-
Looking for the difference in the syntax. The characters are identical; the difference is purely contextual: a call or creation context means spread, a declaration or destructuring context means rest.
-
Calling
...a standalone operator. It is not an operator, it is part of the destructuring and call syntax, so it does not work on its own:const ...rest = arr;is a syntax error. -
Expecting a deep copy. Both spread and rest copy shallowly, so nested objects stay shared.
javascriptconst state = { user: { name: 'Alex' } }; const copy = { ...state }; copy.user.name = 'Maria'; console.log(state.user.name); // Maria -
Putting the rest parameter anywhere but last.
function fn(...args, last) {}does not parse: rest swallows everything that is left, so nothing can follow it. -
Confusing
...argswitharguments. Rest always gives a real array and works in arrow functions, whileargumentsis an array-like object that arrow functions do not have.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.