Toolmingo
Guides7 min read

JavaScript Destructuring: Complete Guide with Examples

Master JavaScript destructuring for arrays and objects. Covers default values, renaming, nested destructuring, rest elements, function parameters, and common pitfalls with practical examples.

Destructuring assignment lets you unpack values from arrays or properties from objects into distinct variables — in a single, readable line. Introduced in ES2015, it has become one of the most-used JavaScript features in modern codebases.


Quick-reference table

Pattern Syntax What it does
Array destructuring const [a, b] = arr Unpacks by position
Object destructuring const { x, y } = obj Unpacks by key name
Default value const [a = 0] = arr Falls back if value is undefined
Rename const { x: newName } = obj Unpacks to a different variable name
Rest element const [first, ...rest] = arr Gathers remaining items
Skip items const [, second] = arr Ignores position with empty comma
Nested const { a: { b } } = obj Digs into nested structures
Swap variables [a, b] = [b, a] No temp variable needed
Function params function f({ x, y }) {} Destructures argument inline
Computed key const { [key]: val } = obj Dynamic property name

Array destructuring

Basic syntax

const colors = ['red', 'green', 'blue'];

const [first, second, third] = colors;
console.log(first);  // 'red'
console.log(second); // 'green'

Skipping elements

Use empty commas to skip positions:

const [, , third] = ['a', 'b', 'c'];
console.log(third); // 'c'

Default values

A default is used only when the unpacked value is undefined (not null, not 0, not ''):

const [a = 10, b = 20] = [5];
console.log(a); // 5  — value present, default ignored
console.log(b); // 20 — undefined, default kicks in

Rest element

The rest element (...name) must always be last:

const [head, ...tail] = [1, 2, 3, 4];
console.log(head); // 1
console.log(tail); // [2, 3, 4]

Swapping variables

let x = 1;
let y = 2;
[x, y] = [y, x];
console.log(x, y); // 2 1

No temporary variable required.

Iterating with index

const fruits = ['apple', 'banana', 'cherry'];

for (const [index, value] of fruits.entries()) {
  console.log(index, value);
}
// 0 'apple'
// 1 'banana'
// 2 'cherry'

Object destructuring

Basic syntax

const user = { name: 'Ana', age: 30, role: 'admin' };

const { name, age } = user;
console.log(name); // 'Ana'
console.log(age);  // 30

Renaming variables

Use originalKey: newName:

const { name: userName, age: userAge } = user;
console.log(userName); // 'Ana'

This is useful when the property name would clash with an existing variable.

Default values

const { name, score = 0 } = { name: 'Ana' };
console.log(score); // 0 — key missing, default used

Combine renaming and defaults:

const { name: userName = 'Guest' } = {};
console.log(userName); // 'Guest'

Rest properties

const { role, ...rest } = { name: 'Ana', age: 30, role: 'admin' };
console.log(role); // 'admin'
console.log(rest); // { name: 'Ana', age: 30 }

Useful for stripping a specific key before passing an object on.

Computed property names

When the key is dynamic:

const key = 'score';
const { [key]: value } = { score: 42 };
console.log(value); // 42

Nested destructuring

Nested objects

const config = {
  server: {
    host: 'localhost',
    port: 3000,
  },
};

const { server: { host, port } } = config;
console.log(host); // 'localhost'
console.log(port); // 3000
// Note: `server` is NOT declared as a variable here

Nested arrays

const matrix = [[1, 2], [3, 4]];
const [[a, b], [c, d]] = matrix;
console.log(a, b, c, d); // 1 2 3 4

Mixed nesting

const data = {
  users: [
    { id: 1, name: 'Ana' },
    { id: 2, name: 'Bob' },
  ],
};

const { users: [firstUser, secondUser] } = data;
console.log(firstUser.name);  // 'Ana'
console.log(secondUser.name); // 'Bob'

Destructuring in function parameters

Instead of accessing opts.host and opts.port inside the function body, destructure the parameter directly:

// Without destructuring
function connect(opts) {
  console.log(opts.host, opts.port);
}

// With destructuring
function connect({ host = 'localhost', port = 3000 } = {}) {
  console.log(host, port);
}

connect({ host: 'example.com' }); // 'example.com' 3000
connect();                         // 'localhost' 3000  ← `= {}` makes opts optional

The = {} at the end makes the whole argument optional — without it, calling connect() with no argument throws TypeError: Cannot destructure property 'host' of undefined.

Array parameter destructuring

function sum([a, b, c = 0]) {
  return a + b + c;
}
console.log(sum([1, 2, 3])); // 6
console.log(sum([1, 2]));    // 3

Destructuring with for...of

const entries = [
  ['name', 'Ana'],
  ['age', 30],
];

for (const [key, value] of entries) {
  console.log(`${key}: ${value}`);
}
// name: Ana
// age: 30

This is exactly how Object.entries() is used in practice:

const obj = { a: 1, b: 2, c: 3 };
for (const [key, value] of Object.entries(obj)) {
  console.log(key, value);
}

Destructuring in imports and exports

ES module destructuring is not "true" destructuring assignment — it uses the same syntax but the semantics are different (live bindings, not copies). Still, visually identical:

// Named imports look like object destructuring:
import { useState, useEffect } from 'react';

// CommonJS destructuring:
const { readFile, writeFile } = require('fs/promises');

Real-world patterns

React props

// Before
function Button(props) {
  return <button className={props.variant}>{props.label}</button>;
}

// After
function Button({ variant = 'primary', label, onClick }) {
  return <button className={variant} onClick={onClick}>{label}</button>;
}

API response parsing

const response = await fetch('/api/user/1');
const { id, name, email, role = 'viewer' } = await response.json();

Swap without temp variable

let a = 'hello', b = 'world';
[a, b] = [b, a];
// a = 'world', b = 'hello'

Extracting first/rest from array

const [first, second, ...others] = fetchedItems;
renderHighlight(first, second);
renderList(others);

Passing only needed fields

function createUser({ name, email }) {
  return db.insert({ name, email }); // ignores extra fields from input
}

Common mistakes

Mistake Problem Fix
const { } = null TypeError: Cannot destructure null Guard: const { x } = obj ?? {}
const [a] = undefined TypeError: undefined is not iterable Guard or default: const [a] = arr ?? []
Forgetting = {} on param Function throws when called without argument function f({ x } = {}) {}
Renaming AND defaulting order const { x = 0: name } — invalid syntax Correct order: const { x: name = 0 }
null bypasses default const [a = 1] = [null]a is null, not 1 Defaults only apply to undefined
Declaring server via nested destructure const { server: { host } } = configserver is not declared Access config.server.host directly if you need server too

TypeScript with destructuring

TypeScript infers types automatically, but you can be explicit:

// Object — type is inferred
const { name, age }: { name: string; age: number } = user;

// Array — tuple annotation
const [status, data]: [number, string] = getResult();

// Function parameter
function greet({ name, age = 0 }: { name: string; age?: number }): string {
  return `${name} is ${age}`;
}

// With interface
interface Config {
  host: string;
  port?: number;
}

function start({ host, port = 8080 }: Config) {
  console.log(host, port);
}

FAQ

1. Does destructuring copy values or create references? For primitives (strings, numbers, booleans) it copies the value. For objects and arrays it copies the reference — the same as a normal variable assignment. Mutating a destructured object property mutates the original.

2. Can I destructure a Map or Set? Not directly with object syntax — they have no own enumerable properties. You can array-destructure a Map.entries() iterator or [...set] spread:

const [[key, val]] = new Map([['a', 1]]);
const [first] = new Set([10, 20, 30]);

3. What's the difference between rest in arrays vs objects? Array rest (...rest) gathers remaining elements (ordered, array). Object rest (...rest) gathers remaining properties (unordered, object). Both produce a new array/object — they do not affect the original.

4. Can I use destructuring on the left side of a regular assignment (not const/let)? Yes, but you need parentheses to avoid the parser treating { as a block:

let a, b;
({ a, b } = { a: 1, b: 2 }); // parentheses required

5. Is there a performance cost? Negligible in practice — modern JS engines optimise destructuring. Don't avoid it for performance reasons; the readability gain is worth it.

6. Does destructuring work with arguments? arguments is array-like but not a true array, so const [a, b] = arguments works. However, using rest params is clearer: function f(...args) { const [a, b] = args; }.

Related tools

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools