JavaScript destructuring, spread, and rest

Unpack objects and arrays into variables, copy with spread, and collect arguments with rest.

JavaScript
const user = { name: "Ada", age: 36, address: { city: "London" } };
const { name, address: { city }, role = "guest" } = user;
console.log(name, city, role);

const updated = { ...user, age: 37 };
console.log(user.age, updated.age, updated.address === user.address);

const [first, , third, ...rest] = [1, 2, 3, 4, 5];
console.log(first, third, rest.join(","));

function total(label, ...numbers) {
  return label + ": " + numbers.reduce((sum, n) => sum + n, 0);
}
console.log(total("sum", 1, 2, 3, 4));

const merged = [...[1, 2], ...[3, 4]];
console.log(merged.join(","));
Output
Ada London guest
36 37 true
1 3 4,5
sum: 10
1,2,3,4

Explanation

Destructuring pulls values out of arrays and objects into variables in one statement. For objects, the names in braces select properties, a colon renames or goes deeper into a nested object, and = gives a default for a missing value. For arrays, the position decides which element is taken, and a gap skips one.

The spread operator ... copies the elements or properties of one value into a new array or object. {...user, age: 37} makes a shallow copy with a changed age, without modifying the original. The same three dots in a function parameter list, the rest parameter, gather the remaining arguments into an array. A shallow copy shares nested objects with the original.

Explore the dry run
Guided walkthroughReady
1const user = { name: "Ada", age: 36, address: { city: "London" } };
2const { name, address: { city }, role = "guest" } = user;
3console.log(name, city, role);
4
5const updated = { ...user, age: 37 };
6console.log(user.age, updated.age, updated.address === user.address);
7
8const [first, , third, ...rest] = [1, 2, 3, 4, 5];
9console.log(first, third, rest.join(","));
10
11function total(label, ...numbers) {
12 return label + ": " + numbers.reduce((sum, n) => sum + n, 0);
13}
14console.log(total("sum", 1, 2, 3, 4));
15
16const merged = [...[1, 2], ...[3, 4]];
17console.log(merged.join(","));

Follow the example

Start to inspect the source, values, and output. These prepared steps explain the published sample; grouped loop steps describe multiple iterations.

View the complete dry-run table
Prepared trace of the published program. Some rows group repeated iterations.
Step / lineWhat happensState after stepOutput so far
Take name, reach into address to get city, and use "guest" because user has no role.—
—
Three variables from one statement.—
Ada London guest
A new object with the same properties and a changed age.—
Ada London guest
The original is unchanged, but the nested address object is shared, because the copy is shallow.—
Ada London guest
36 37 true
The empty slot skips 2; rest collects what is left.—
Ada London guest
36 37 true
first is 1, third is 3, and rest is [4, 5].—
Ada London guest
36 37 true
1 3 4,5
The rest parameter numbers is [1, 2, 3, 4].—
Ada London guest
36 37 true
1 3 4,5
sum: 10
Spreading two arrays into one literal concatenates them.—
Ada London guest
36 37 true
1 3 4,5
sum: 10
1,2,3,4

Cost and common mistakes

Copying with spread is O(n) in the number of properties or elements.

  • Spread makes a shallow copy. Changing updated.address.city also changes user.address.city. Use structuredClone for a deep copy.
  • Destructuring null or undefined throws a TypeError. Provide a default object when the value may be missing.
  • Properties on the right of a spread override those on the left, so the order matters.

Try it yourself

How would you swap two variables with destructuring?

Reveal answer and reasoning

[a, b] = [b, a]; the right side builds a new array first, and the left side unpacks it.

Further reading