Skip to content

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.

Copy an array:

const original = [1, 2, 3];
const copy = [...original];
copy.push(4);
console.log(original); // [1, 2, 3] — unchanged
console.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 dynamically
const withNew = [...expenses.slice(0, 1), newExpense, ...expenses.slice(1)];

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'

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 amount
const 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.

function addExpense(expenses, newExpense) {
return [...expenses, newExpense];
}
const with coffee = addExpense([], new Expense({ description: 'Coffee', amount: 4.50, category: 'Food' }));

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)); // 30
  1. Create a copy of the expenses array using spread. Add a new item to the copy and confirm the original is unchanged.
  2. Merge { category: 'Other' } with { description: 'Coffee', amount: 4.50 } using spread. Confirm the result.
  3. Write an updateExpense(expenses, id, changes) function using map and spread. Test it by updating the amount of expense with id 1.
  4. Write an addExpense(expenses, expense) function that returns a new array with the new expense appended.
  5. 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.