Three Dots, Two Jobs
JavaScript Rest & Spread
The `...` operator collects values into an array (rest) or spreads them out (spread). Same syntax, opposite directions.
What you'll learn
- Use `...args` to accept any number of arguments
- Use `...arr` to spread an array into a call or literal
- Spread objects (ES2018+)
The ... operator does two jobs — opposite directions, same syntax.
| Context | What ... does |
|---|---|
| Function PARAMETER | Rest — collect remaining args into array |
| Function CALL site | Spread — expand an iterable into args |
| Array literal | Spread — expand items |
| Object literal | Spread — copy properties (ES2018) |
Rest — Collect Arguments
A rest parameter gathers all remaining arguments into a real array.
function sum(...nums) {
let total = 0;
for (const n of nums) total += n;
return total;
}
console.log(sum(1, 2, 3)); // 6
console.log(sum(10, 20, 30, 40)); // 100
console.log(sum()); // 0 The rest parameter must be last in the parameter list.
function greetAll(greeting, ...names) {
for (const name of names) {
console.log(`${greeting}, ${name}!`);
}
}
greetAll("Hello", "Ada", "Lin", "Tim");
// "Hello, Ada!"
// "Hello, Lin!"
// "Hello, Tim!" Spread — Expand an Array
...arr in a call site expands the array’s items into separate
arguments.
function add(a, b, c) {
return a + b + c;
}
const nums = [1, 2, 3];
console.log(add(...nums)); // 6 ← same as add(1, 2, 3) A famous case: Math.max/Math.min take individual arguments, not
an array. Spread bridges the gap:
const scores = [88, 92, 73, 95, 81];
console.log(Math.max(...scores)); // 95
console.log(Math.min(...scores)); // 73 Spread Into an Array Literal
Combine, copy, or insert:
const a = [1, 2];
const b = [3, 4];
const combined = [...a, ...b]; // [1, 2, 3, 4]
const withMore = [0, ...a, 5, ...b]; // [0, 1, 2, 5, 3, 4]
const copy = [...a]; // [1, 2] — new array, same items
console.log(combined, withMore, copy); [...arr] is the cleanest way to copy an array.
Spread Into an Object Literal
Same idea for objects — copy and override properties.
const defaults = { theme: "light", fontSize: 14 };
const user = { fontSize: 16, language: "en" };
const settings = { ...defaults, ...user };
console.log(settings);
// { theme: 'light', fontSize: 16, language: 'en' } Later spreads override earlier ones, so user.fontSize wins over
defaults.fontSize. This is the standard immutable-update pattern.
Rest in Destructuring (Refresher)
You’ve already seen rest in destructuring:
const [first, ...others] = [1, 2, 3, 4];
console.log(first); // 1
console.log(others); // [2, 3, 4]
const { a, ...rest } = { a: 1, b: 2, c: 3 };
console.log(a); // 1
console.log(rest); // { b: 2, c: 3 } Try It Yourself
Exercise
Sum any number of arguments
// declare sum here
console.log(sum(1, 2, 3));
console.log(sum(10, 20, 30, 40));
console.log(sum());
💡 Show hint
✅ Show solution
function sum(...nums) {
return nums.reduce((a, b) => a + b, 0);
}
console.log(sum(1, 2, 3));
console.log(sum(10, 20, 30, 40));
console.log(sum());
Up Next
The most-used function syntax in modern JavaScript — arrow functions.
JavaScript Arrow Functions →