The Rest Parameter
Spread expands a collection outward. Rest collects individual items inward. They use the same ... syntax but in opposite positions.
Rest in function parameters
Section titled “Rest in function parameters”A rest parameter collects all remaining function arguments into an array:
function logAll(...items) { items.forEach(item => console.log(item));}
logAll('Coffee', 'Lunch', 'Dinner');// 'Coffee'// 'Lunch'// 'Dinner'items is a real array — you can call forEach, map, filter, and any other array method on it.
Rest after named parameters
Section titled “Rest after named parameters”Rest parameters can follow named parameters. They collect everything that was not already captured:
function logExpenses(label, ...expenses) { console.log(`${label}:`); expenses.forEach(e => console.log(` ${e.description}: $${e.amount.toFixed(2)}`));}
logExpenses('Food expenses', coffeeExpense, lunchExpense, dinnerExpense);// 'Food expenses:'// ' Coffee: $4.50'// ' Lunch: $12.75'// ' Dinner out: $38.20'The rest parameter must always be last — you cannot put a parameter after ...rest.
Rest in destructuring (object)
Section titled “Rest in destructuring (object)”In object destructuring, rest collects all properties that were not explicitly extracted:
const expense = { id: 1, description: 'Coffee', amount: 4.50, category: 'Food', date: '2024-01-15' };
const { id, ...rest } = expense;console.log(id); // 1console.log(rest); // { description: 'Coffee', amount: 4.50, category: 'Food', date: '2024-01-15' }The variable id gets its value; everything else goes into rest as a new object.
This is the pattern used in the RecurringExpense constructor from Module 02:
constructor({ recurrence, ...rest }) { super(rest); // passes everything except recurrence to the parent constructor this.recurrence = recurrence;}The subclass pulls out what it specifically needs (recurrence) and passes the remainder to super — no need to list every parent property explicitly.
Rest in destructuring (array)
Section titled “Rest in destructuring (array)”[first, ...remaining] collects everything after the first element:
const [head, ...tail] = [1, 2, 3, 4, 5];console.log(head); // 1console.log(tail); // [2, 3, 4, 5]Spread vs rest — the same syntax, opposite meaning
Section titled “Spread vs rest — the same syntax, opposite meaning”| Position | Name | What it does |
|---|---|---|
Function call: fn(...arr) | Spread | Expands array into arguments |
Function parameter: fn(...args) | Rest | Collects arguments into array |
Assignment right side: { ...obj } | Spread | Copies/merges properties out |
Assignment left side: const { a, ...rest } = obj | Rest | Collects remaining properties |
The rule: spread is on the right (expanding out), rest is on the left (collecting in).
A practical BudgetBuddy use
Section titled “A practical BudgetBuddy use”When you want to update an expense’s description and amount but preserve all other fields, use rest to separate the changed fields from the unchanged ones:
function applyUpdate(expense, updates) { const { id, createdAt, ...mutableFields } = expense; const updatedFields = { ...mutableFields, ...updates }; return { id, createdAt, ...updatedFields };}id and createdAt are protected — they are pulled out first and then explicitly put back, so updates cannot accidentally overwrite them even if it contains those keys.
Exercise
Section titled “Exercise”- Write a function
sum(...numbers)using a rest parameter that returns the total of all arguments. Call it with 3, 5, and 7 separate arguments. - Destructure
idandcreatedAtfrom an expense object and collect the remaining fields intofields. - Write
applyUpdate(expense, updates)as shown above and test it by changingamountwithout touchingid. - Use
[first, ...rest]to split the BudgetBuddy expenses array into the first expense and the remaining ones.
...restin function parameter position collects remaining arguments into an array.const { a, ...rest } = objcollects all properties not explicitly extracted.const [first, ...rest] = arrcollects all elements after the first.- Rest must always be the last item in a parameter or destructuring pattern.
- Same syntax (
...) as spread, but rest is on the left (collecting), spread is on the right (expanding).