learn.colinkim.dev

Destructuring and spread/rest

Learn how to extract values from objects and arrays with destructuring, and how spread and rest simplify copying and combining data.

Destructuring lets you pull values out of objects and arrays into named variables in a single line. Spread and rest use the same ... syntax for two different jobs: expanding data into individual elements, or collecting elements into a single container.

These patterns appear everywhere in modern JavaScript.

Object destructuring

The basic form extracts properties by name:

const user = { name: "Ada", age: 36, email: "ada@example.com" };

const { name, age } = user;

console.log(name);  // "Ada"
console.log(age);   // 36

The variable names must match the property names. You are essentially saying “give me the name and age properties from user.”

Renaming during destructuring

When property names conflict with existing variables or are inconvenient, rename them:

const { name: userName, age: userAge } = user;

console.log(userName);  // "Ada"
console.log(userAge);   // 36

The syntax is { originalName: newVariableName }.

Default values

Destructuring supports defaults when a property might be missing:

const { role = "user" } = user;
// role is "user" because user.role is undefined

Defaults only kick in for undefined, just like function parameter defaults.

Nested destructuring

You can destructure nested objects in one pattern:

const company = {
  name: "Example Corp",
  address: { city: "Portland", state: "OR" },
};

const { address: { city, state } } = company;

console.log(city);   // "Portland"
console.log(state);  // "OR"

Array destructuring

Arrays destructure by position instead of name:

const coordinates = [3, 4];
const [x, y] = coordinates;

console.log(x);  // 3
console.log(y);  // 4

Skipping elements

Use empty commas to skip positions you do not need:

const date = [2024, 3, 15];
const [, month, day] = date;

console.log(month);  // 3
console.log(day);    // 15

Default values

const [first, second, third = "default"] = ["a", "b"];
// third is "default" because the array has no third element

Swapping variables

Destructuring makes swapping values clean:

let a = 1;
let b = 2;

[a, b] = [b, a];

console.log(a);  // 2
console.log(b);  // 1

Destructuring in function parameters

Functions commonly destructure their arguments:

function greet({ name, greeting = "Hello" }) {
  return `${greeting}, ${name}!`;
}

greet({ name: "Ada" });                    // "Hello, Ada!"
greet({ name: "Ada", greeting: "Hi" });    // "Hi, Ada!"

This replaces accessing properties by name inside the function body and makes the expected shape explicit in the parameter list.

Destructuring arrays from function returns

function minMax(numbers) {
  return [Math.min(...numbers), Math.max(...numbers)];
}

const [min, max] = minMax([3, 1, 4, 1, 5]);
// min: 1, max: 5

Spread syntax

Spread expands an iterable into individual elements. It uses the same ... as rest, but in a different position.

Spreading arrays

Spread inserts each element as a separate item:

const defaults = [0, 0, 0];
const overrides = [1, 2];

const combined = [...defaults, ...overrides];
// [0, 0, 0, 1, 2]

Insert elements anywhere:

const middle = [...defaults, 99, ...overrides];
// [0, 0, 0, 99, 1, 2]

Spreading objects

Spread copies an object’s enumerable properties into a new object:

const base = { name: "Ada", role: "engineer" };
const updated = { ...base, role: "senior engineer" };
// { name: "Ada", role: "senior engineer" }

Later properties overwrite earlier ones, so put defaults first and overrides last.

Spreading in function calls

Spread passes array elements as individual arguments:

const numbers = [1, 2, 3];

Math.max(...numbers);  // 3 — equivalent to Math.max(1, 2, 3)

Rest syntax

Rest collects remaining elements into a single container. It is the inverse of spread.

Rest in function parameters

function logAll(first, ...rest) {
  console.log("First:", first);
  console.log("Rest:", rest);
}

logAll("a", "b", "c", "d");
// First: a
// Rest: ["b", "c", "d"]

Rest in destructuring

Rest in array destructuring captures remaining elements:

const [first, second, ...remaining] = [1, 2, 3, 4, 5];

console.log(first);     // 1
console.log(second);    // 2
console.log(remaining); // [3, 4, 5]

Rest in object destructuring captures remaining properties:

const { name, ...rest } = { name: "Ada", age: 36, role: "engineer" };

console.log(name);  // "Ada"
console.log(rest);  // { age: 36, role: "engineer" }

This is useful for separating concerns — extracting one property and passing the rest along:

function createUser({ password, ...safeData }) {
  // password is excluded — do not pass it to the API
  return api.post("/users", safeData);
}

What to carry forward

  • destructuring extracts values into variables — objects by name, arrays by position
  • rename properties during destructuring with { original: newName }
  • defaults work in destructuring just like in function parameters
  • spread expands data into individual elements — useful for copying, merging, and function calls
  • rest collects remaining elements into an array or object
  • spread and rest use the same ... syntax but in different positions and for different purposes
  • all spreading and copying is shallow — nested data is shared by reference

These patterns make data extraction and combination concise and readable. The next lesson covers the critical topic of copying versus mutating data.

Progress

Quick checks

No quick checks in this lesson.

Mark lesson manually or answer quick checks to track progress.