The Spread Operator
The spread operator (...) expands the elements of an array or the properties of an object into a new expression. It is the primary tool for creating copies and merging values without mutating the originals.
Spreading arrays
Section titled “Spreading arrays”Copy an array:
const original = [1, 2, 3];const copy = [...original];
copy.push(4);console.log(original); // [1, 2, 3] — unchangedconsole.log(copy); // [1, 2, 3, 4]Merge two arrays:
const foodExpenses = [{ description: 'Coffee', amount: 4.50 }];const transportExpenses = [{ description: 'Bus pass', amount: 30.00 }];
const allExpenses = [...foodExpenses, ...transportExpenses];Insert items at any position:
const expenses = [expense1, expense3];const updated = [expense1, newExpense, expense3];
// With spread and a known position — or build dynamicallyconst withNew = [...expenses.slice(0, 1), newExpense, ...expenses.slice(1)];Spreading objects
Section titled “Spreading objects”Copy an object:
const expense = { id: 1, description: 'Coffee', amount: 4.50, category: 'Food' };const copy = { ...expense };Merge two objects (later properties override earlier ones):
const defaults = { category: 'Other', date: '2024-01-01' };const overrides = { description: 'Coffee', amount: 4.50, category: 'Food' };
const merged = { ...defaults, ...overrides };// { category: 'Food', date: '2024-01-01', description: 'Coffee', amount: 4.50 }// 'Food' overrides 'Other'Updating an object immutably
Section titled “Updating an object immutably”The most important use case in BudgetBuddy: update a specific field on an object without mutating the original.
const expense = { id: 1, description: 'Coffee', amount: 4.50, category: 'Food' };
// Update just the amountconst updated = { ...expense, amount: 5.25 };// { id: 1, description: 'Coffee', amount: 5.25, category: 'Food' }The spread copies every property from expense, then amount: 5.25 overrides the copied amount. The original is unchanged.
This is the pattern for updating an item in the BudgetBuddy expenses array:
function updateExpense(expenses, id, changes) { return expenses.map(e => e.id === id ? { ...e, ...changes } : e);}
const updated = updateExpense(expenses, 1, { amount: 5.25 });map returns a new array. For the matching expense, spread creates a new object with the changes applied. For all others, the original object is returned unchanged. The original expenses array is never mutated.
Adding a new expense without mutation
Section titled “Adding a new expense without mutation”function addExpense(expenses, newExpense) { return [...expenses, newExpense];}
const with coffee = addExpense([], new Expense({ description: 'Coffee', amount: 4.50, category: 'Food' }));Spread in function calls
Section titled “Spread in function calls”Spread can also expand an array into individual function arguments:
const values = [4.50, 30.00, 12.75];const total = values.reduce((a, b) => a + b, 0);
// Or if you have a function that takes individual args:console.log(Math.max(...values)); // 30Exercise
Section titled “Exercise”- Create a copy of the expenses array using spread. Add a new item to the copy and confirm the original is unchanged.
- Merge
{ category: 'Other' }with{ description: 'Coffee', amount: 4.50 }using spread. Confirm the result. - Write an
updateExpense(expenses, id, changes)function usingmapand spread. Test it by updating theamountof expense with id 1. - Write an
addExpense(expenses, expense)function that returns a new array with the new expense appended. - Use
Math.max(...expenses.map(e => e.amount))to find the largest amount without a manual loop.
[...array]creates a shallow copy of an array.{ ...obj }creates a shallow copy of an object.- Merge arrays with
[...a, ...b]and objects with{ ...a, ...b }— later keys override earlier ones. - Update a field immutably:
{ ...obj, field: newValue }. - Update an item in an array:
expenses.map(e => e.id === id ? { ...e, ...changes } : e). - Spread in function calls expands an array into individual arguments.