Rest Operator
Rest syntax collects multiple values into one array or object.
It uses the same three dots as spread:
...But rest does the opposite of spread.
Spread expands values.
Rest collects values.
Rest Parameters
Rest parameters collect extra function arguments into an array.
function sum(...numbers) {
return numbers.reduce((total, number) => total + number, 0);
}
console.log(sum(1, 2, 3)); // 6
console.log(sum(5, 10, 15, 20)); // 50Inside the function, numbers is a real array.
function showValues(...values) {
console.log(Array.isArray(values));
}
showValues(1, 2, 3); // trueRest Parameter Must Be Last
A rest parameter must be the final parameter.
function logUser(role, ...names) {
console.log(role);
console.log(names);
}
logUser("admin", "Alice", "Bob");Output:
admin
["Alice", "Bob"]This is invalid:
function broken(...names, role) {}JavaScript would not know how many arguments belong to names.
Rest With Array Destructuring
Rest can collect remaining array items.
const numbers = [1, 2, 3, 4];
const [first, ...rest] = numbers;
console.log(first); // 1
console.log(rest); // [2, 3, 4]The rest variable gets the remaining items.
You can name it whatever makes sense:
const [primary, ...others] = users;Rest With Object Destructuring
Rest can collect remaining object properties.
const user = {
name: "Alice",
role: "admin",
password: "secret",
};
const { password, ...publicUser } = user;
console.log(publicUser);
// { name: "Alice", role: "admin" }This is useful when you want a new object without one or more properties.
Rest Creates a New Array or Object
Rest creates a new array or object for the collected values.
const numbers = [1, 2, 3];
const [first, ...others] = numbers;
console.log(others); // [2, 3]
console.log(others === numbers); // falseFor objects:
const user = {
name: "Alice",
role: "admin",
};
const { name, ...details } = user;
console.log(details); // { role: "admin" }Like spread, this is shallow.
Nested objects are still references.
Rest vs arguments
Before rest parameters, JavaScript had the arguments object.
function showArguments() {
console.log(arguments);
}
showArguments("a", "b");But arguments is not a real array.
Rest parameters are clearer and easier to use.
function showArguments(...args) {
console.log(args.map((value) => value.toUpperCase()));
}
showArguments("a", "b"); // ["A", "B"]Prefer rest parameters in modern JavaScript.
Rest vs Spread
The same ... syntax can mean rest or spread depending on where it appears.
Rest collects:
function sum(...numbers) {
return numbers.length;
}Spread expands:
const numbers = [1, 2, 3];
sum(...numbers);Rest appears in places that receive values:
- function parameters
- array destructuring
- object destructuring
Spread appears in places that provide values:
- function calls
- array literals
- object literals
Practical Example: Flexible Logging
function log(level, ...messages) {
const text = messages.join(" ");
console.log(`[${level}] ${text}`);
}
log("INFO", "User", "logged", "in");
// [INFO] User logged inThe first argument has a specific meaning.
All remaining arguments become messages.
Practical Example: Removing Sensitive Data
const user = {
id: 1,
name: "Alice",
password: "secret",
token: "abc123",
};
const { password, token, ...safeUser } = user;
console.log(safeUser);
// { id: 1, name: "Alice" }This pattern is common when preparing data to display or return from a function.
Best Practices
Use rest parameters instead of arguments:
function fn(...args) {}Keep rest parameters last:
function createUser(role, ...names) {}Use rest destructuring to separate known values from remaining values:
const { id, ...details } = user;Use clear names:
const [firstUser, ...remainingUsers] = users;Common Mistakes
Mistake 1: Putting Rest Before Another Parameter
function broken(...items, last) {}Rest must be last.
Mistake 2: Confusing Rest With Spread
function sum(...numbers) {}This is rest because it collects arguments.
sum(...numbers);This is spread because it expands an array into arguments.
Mistake 3: Expecting Rest to Deep-Copy Nested Objects
const { id, ...details } = user;This creates a shallow copy of remaining properties.
Nested objects are still shared references.
Quick Check
What does this log?
function collect(first, ...others) {
console.log(first);
console.log(others);
}
collect("a", "b", "c");It logs:
a
["b", "c"]What does this log?
const [first, ...rest] = [10, 20, 30];
console.log(rest);It logs:
[20, 30]Summary
Rest syntax collects values.
- Rest uses
.... - Rest parameters collect function arguments into an array.
- Rest parameters must be last.
- Array rest collects remaining array items.
- Object rest collects remaining object properties.
- Rest creates shallow copies.
- Rest collects values; spread expands values.
- Prefer rest parameters over the old
argumentsobject.