Skip to main content

Destructuring: Arrays and Objects in JavaScript

Published: December 18, 2025 Updated: August 30, 2026 Larry Qu 7 min read

Destructuring is a syntax feature that lets you unpack values from arrays and properties from objects into distinct variables. It was introduced in ES6 and has become one of the most frequently used JavaScript features — you’ll see it in nearly every modern codebase for extracting API response fields, function parameters, and import/export patterns.

The core value is readability: instead of accessing properties repeatedly through dot notation, destructuring makes the intent explicit at the point of assignment.

Array Destructuring

Array destructuring extracts values by position. The pattern on the left mirrors the structure of the array on the right:

const coordinates = [40.7128, -74.0060];
const [lat, lng] = coordinates;
console.log(lat); // 40.7128
console.log(lng); // -74.0060

You can skip positions with commas, collect remaining elements with rest (...), and provide defaults for missing positions:

const [first, , third] = [1, 2, 3];        // skip index 1
console.log(first, third); // 1, 3

const [head, ...tail] = [1, 2, 3, 4, 5];   // head=1, tail=[2,3,4,5]

const [x = 0, y = 0, z = 0] = [10, 20];    // z defaults to 0 (position not in array)
console.log(x, y, z); // 10, 20, 0

Variable Swapping

Swapping two variables without a temporary variable is one of the cleaner uses of array destructuring:

let a = 'left';
let b = 'right';
[a, b] = [b, a];
console.log(a, b); // 'right', 'left'

Before this, you needed a third variable to hold the intermediate value.

Returning Multiple Values from Functions

Functions can only return one value, but that value can be an array, and destructuring lets you capture the parts clearly:

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

const [min, max] = minMax([3, 1, 4, 1, 5, 9, 2, 6]);
console.log(min, max); // 1, 9

Object Destructuring

Object destructuring extracts properties by name — position doesn’t matter. The left side lists the property names you want to extract:

const user = { id: 1, name: 'Alice', email: '[email protected]', role: 'admin' };

const { name, email } = user;
console.log(name);   // 'Alice'
console.log(email);  // '[email protected]'
// Properties not listed (id, role) are simply not extracted

Renaming

When the property name conflicts with an existing variable or you want a different local name, use : to rename:

const { name: userName, role: userRole } = user;
console.log(userName); // 'Alice'
console.log(userRole); // 'admin'

Default Values

Defaults apply when the property is undefined (missing from the object or explicitly set to undefined):

const config = { host: 'localhost' };

const { host, port = 3000, ssl = false } = config;
console.log(host); // 'localhost'
console.log(port); // 3000  (default — not in config)
console.log(ssl);  // false (default — not in config)

Defaults and renaming can be combined: { port: serverPort = 3000 } extracts port, renames it to serverPort, and defaults to 3000.

Rest Properties

Collect remaining properties into a new object with ...:

const { id, password, ...safeUser } = { id: 1, name: 'Alice', email: '[email protected]', password: 'secret' };
// safeUser = { name: 'Alice', email: '[email protected]' } — password excluded
// Useful when you want to strip sensitive fields before sending to a client

Nested Destructuring

Access deeply nested properties by mirroring the structure:

const response = {
  status: 200,
  data: {
    user: {
      id: 42,
      name: 'Alice',
      address: { city: 'New York', zip: '10001' }
    }
  }
};

const { data: { user: { name, address: { city } } } } = response;
console.log(name); // 'Alice'
console.log(city); // 'New York'

Nested destructuring can get hard to read. If the nesting is more than two levels deep, consider extracting intermediate variables:

// More readable — intermediate variable breaks the depth
const { data: { user } } = response;
const { name, address: { city } } = user;

Destructuring in Function Parameters

Destructuring parameters is common in React (props), Redux (reducers), and any function that accepts option objects. It documents exactly which properties the function uses:

// Without destructuring — you have to read the function body to know what's used
function createUser(options) {
  const name     = options.name;
  const role     = options.role || 'user';
  const active   = options.active !== undefined ? options.active : true;
  return { name, role, active };
}

// With destructuring — the signature is self-documenting
function createUser({ name, role = 'user', active = true } = {}) {
  return { name, role, active };
}

createUser({ name: 'Alice' });                          // { name: 'Alice', role: 'user', active: true }
createUser({ name: 'Bob', role: 'admin', active: false }); // { name: 'Bob', role: 'admin', active: false }
createUser();                                           // { name: undefined, role: 'user', active: true }

The = {} default at the end means calling createUser() with no arguments works instead of throwing “Cannot destructure property ’name’ of undefined.”

For React function components, destructuring props directly in the parameter is the standard pattern:

function UserCard({ name, email, role = 'user', onEdit }) {
  return (
    <div>
      <h3>{name}</h3>
      <p>{email}</p>
      <span>{role}</span>
      <button onClick={onEdit}>Edit</button>
    </div>
  );
}

Real-World Patterns

Extracting API Response Fields

When working with API responses, you typically want specific nested fields — destructuring makes the extraction clear and concise:

async function loadProfile(userId) {
  const res = await fetch(`/api/users/${userId}`);
  const { data: { name, email, avatar }, meta: { lastLogin } } = await res.json();

  return { name, email, avatar, lastLogin };
}

Iterating Objects

Object.entries() returns [key, value] pairs, which combine naturally with array destructuring in loops:

const scores = { alice: 95, bob: 87, carol: 92 };

for (const [name, score] of Object.entries(scores)) {
  console.log(`${name}: ${score}`);
}

// Also useful with .map()
const rankings = Object.entries(scores)
  .sort(([, a], [, b]) => b - a)  // sort by score descending
  .map(([name, score], index) => `${index + 1}. ${name} (${score})`);

Filtering and Transforming Arrays of Objects

Destructuring inside .map() and .filter() makes transformations readable:

const users = [
  { id: 1, name: 'Alice', active: true,  role: 'admin' },
  { id: 2, name: 'Bob',   active: false, role: 'user' },
  { id: 3, name: 'Carol', active: true,  role: 'user' },
];

// Extract only the fields needed for a dropdown
const options = users
  .filter(({ active }) => active)
  .map(({ id, name }) => ({ value: id, label: name }));
// [{ value: 1, label: 'Alice' }, { value: 3, label: 'Carol' }]

Import Destructuring

ES module imports use the same destructuring syntax — you’re extracting named exports from a module’s exported object:

import { useState, useEffect, useCallback } from 'react';
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';

Common Mistakes

Destructuring null or undefined throws a TypeError. Guard when the source might be missing:

// ❌ Throws if response.data is null
const { user } = response.data;

// ✅ Provide a fallback
const { user } = response.data ?? {};
// or check first
if (response.data) {
  const { user } = response.data;
}

Object destructuring at statement start requires parens when used without const/let/var, because { at the start of a statement is parsed as a block:

let name, age;
// ❌ SyntaxError — { is parsed as a block statement
{ name, age } = { name: 'Alice', age: 30 };

// ✅ Wrap in parens
({ name, age } = { name: 'Alice', age: 30 });

Summary

Destructuring reduces boilerplate and makes data shapes explicit. The patterns you’ll use most often:

  • const { a, b } = obj — extract named properties
  • const { a: localName, b = default } = obj — rename and default
  • const [first, ...rest] = arr — head and tail of an array
  • const { sensitive, ...safe } = obj — strip properties with rest
  • function f({ option = default } = {}) — self-documenting option objects

The syntax always mirrors the shape of the data you’re extracting from.

Resources

Comments

👍 Was this article helpful?