Complete JavaScript Course Module 7: Intermediate: Objects and JSON

Destructuring, Spread and Rest in JavaScript

  • Beginner
  • Lesson 7.3
  • 5 min read
  • 29 of 76 in the course

In short

Destructuring, spread and rest in JavaScript let you unpack values from arrays and objects, copy and merge them, and collect extra arguments, all with short modern syntax. What is destructuring in JavaScript?

Destructuring, spread and rest in JavaScript let you unpack values from arrays and objects, copy and merge them, and collect extra arguments, all with short modern syntax.

What is destructuring in JavaScript?

Destructuring means pulling values out of an array or object and saving them into variables in one step. Think of unpacking a grocery bag: instead of reaching in again and again, you take everything out and put each item on the shelf at once.

Array destructuring

With arrays, you use square brackets on the left side of =. Variables are filled by position.

const rgb = [255, 128, 0];

const [red, green, blue] = rgb;
console.log(red, green, blue);
// Output: 255 128 0

const [first, , third] = ["gold", "silver", "bronze"];
console.log(first, third);
// Output: gold bronze

let a = 1;
let b = 2;
[a, b] = [b, a];
console.log(a, b);
// Output: 2 1

A blank space between commas skips an item. The last example shows a neat trick: swapping two variables without a temporary variable.

Object destructuring, renaming and default values

With objects, you use curly braces, and variables are matched by key name, not position.

const user = {
  name: "Kai",
  email: "kai@example.com",
  role: "editor",
};

const { name, email } = user;
console.log(name, email);
// Output: Kai kai@example.com

const { role: userRole } = user;
console.log(userRole);
// Output: editor

const { theme = "light", name: displayName = "Guest" } = user;
console.log(theme, displayName);
// Output: light Kai

Here is what each part does:

  • { name, email } creates variables named after the keys.
  • { role: userRole } reads role but stores it in a variable called userRole. This is renaming.
  • { theme = "light" } gives a default value when the property is missing or undefined. user has no theme, so it becomes "light".
  • You can combine renaming and a default: name: displayName = "Guest".

Destructuring function parameters

This is one of the most useful patterns. When a function takes an options object, you can destructure it right in the parameter list. Defaults make the options optional.

const formatPrice = ({ amount, currency = "USD", decimals = 2 }) => {
  return `${amount.toFixed(decimals)} ${currency}`;
};

console.log(formatPrice({ amount: 19.5 }));
// Output: 19.50 USD
console.log(formatPrice({ amount: 7, currency: "EUR", decimals: 0 }));
// Output: 7 EUR

The caller passes one object, and the function picks out the values it needs. The order of keys does not matter, which makes calls easy to read.

Common mistake: Destructuring undefined. If someone calls formatPrice() with no argument, you get a TypeError. Add a default for the whole parameter: ({ amount = 0, currency = "USD" } = {}) => ....

How to use the spread operator with arrays and objects

The spread syntax ... spreads the items of an array, or the properties of an object, into a new one. It is perfect for copying and merging without changing the originals.

const basics = ["HTML", "CSS"];
const skills = [...basics, "JavaScript"];
console.log(skills);
// Output: ["HTML", "CSS", "JavaScript"]

const defaults = { theme: "light", fontSize: 16, sound: true };
const userPrefs = { theme: "dark" };

const settings = { ...defaults, ...userPrefs };
console.log(settings);
// Output: { theme: "dark", fontSize: 16, sound: true }

const updatedUser = { ...user, role: "admin" };
console.log(updatedUser.role, user.role);
// Output: admin editor

When you merge objects, later properties win. That is why theme is "dark": userPrefs comes after defaults. The last example creates an updated copy of user while the original stays the same, a pattern used a lot in modern frameworks.

You can also spread an array into a function call: Math.max(...[3, 9, 4]) returns 9.

Rest parameters: collect the remaining values

Rest uses the same three dots, but does the opposite job: it collects several values into one array. Use it in function parameters to accept any number of arguments, or in destructuring to grab "everything else".

const sum = (...numbers) => numbers.reduce((total, n) => total + n, 0);
console.log(sum(5, 10, 15));
// Output: 30

const [winner, ...others] = ["Zoe", "Max", "Lin"];
console.log(winner, others);
// Output: Zoe ["Max", "Lin"]

const { password, ...safeUser } = { id: 7, name: "Ivy", password: "secret" };
console.log(safeUser);
// Output: { id: 7, name: "Ivy" }

The last line is a handy way to remove a sensitive field before showing or sending data. A rest element must always come last.

Tip: Easy rule: ... on the right side of = or in a function call is spread (it expands). ... on the left side or in a parameter list is rest (it collects).

Shallow copies and structuredClone

Spread makes a shallow copy. Only the top level is copied. Nested objects and arrays are still shared between the original and the copy.

const profile = { name: "Rae", address: { city: "Rome" } };

const shallow = { ...profile };
shallow.address.city = "Milan";
console.log(profile.address.city);
// Output: Milan  (the original changed too!)

const deep = structuredClone(profile);
deep.address.city = "Turin";
console.log(profile.address.city);
// Output: Milan  (the original is safe)

structuredClone() is built into all modern browsers and makes a deep copy, copying every level. Use it when your data is nested. It cannot copy functions, so it suits plain data like settings or API results.

Practice exercise

Given const movie = { title: "Up", year: 2009, ratings: [8, 9, 7] };:

  1. Destructure title and year, renaming year to releaseYear.
  2. Destructure the first rating into firstRating and the rest into otherRatings.
  3. Create updatedMovie, a copy of movie with year set to 2010 and a new genre property.
  4. Write a function average(...nums) and call it with the ratings spread in.

Hint: For step 2, destructure movie.ratings with [firstRating, ...otherRatings]. For step 4, call average(...movie.ratings).

Key takeaways

  • Destructuring unpacks arrays by position and objects by key name.
  • You can rename (role: userRole) and set defaults (theme = "light") while destructuring.
  • Spread ... copies and merges arrays and objects; later object properties win.
  • Rest ... collects remaining values into an array or object and must come last.
  • Spread copies are shallow; use structuredClone() for a deep copy of nested data.