ESC

Type to search the knowledge base.

Destructuring Objects and Arrays

Object and array destructuring — renames, defaults, nested patterns, rest, and parameter destructuring in real APIs.

beginner3 min read
  • javascript
  • destructuring
  • objects
  • arrays

Destructuring unpacks values from objects and arrays into variables. It’s syntax sugar you will see in every React props list and every const { data } = await res.json() — and interviewers will ask about defaults, renames, and what happens with undefined.

Objects

const user = { id: 1, name: 'Ada', role: 'admin' };

const { name, role } = user;
// name = 'Ada', role = 'admin'

const { name: displayName, role: r } = user; // rename
const { email = 'n/a' } = user; // default when undefined

const { id, ...rest } = user;
// rest = { name: 'Ada', role: 'admin' }

Defaults apply when the property value is undefined (missing counts as undefined), not when it’s null:

const { a = 1 } = { a: null };
// a === null

Nested

const res = {
  data: {
    user: { name: 'Ada' },
    meta: { page: 1 },
  },
};

const {
  data: {
    user: { name },
    meta: { page },
  },
} = res;

Deep destructuring throws if an intermediate value is null/undefined. Guard with defaults:

const {
  data: { user } = {},
} = resMaybe;

Arrays

const pair = ['left', 'right', 'extra'];
const [l, r] = pair;
const [, second] = pair; // skip
const [first, ...tail] = pair;

const [a = 0, b = 0] = []; // defaults

Swap without temp:

let x = 1;
let y = 2;
[x, y] = [y, x];

Function parameters

function connect({ host = 'localhost', port = 5432, ssl = true } = {}) {
  return `${host}:${port} ssl=${ssl}`;
}

connect();
connect({ port: 15432 });

The trailing = {} allows zero-argument calls. Same pattern appears in React components: function Avatar({ size = 32, src }).

Computed property names

const key = 'name';
const { [key]: value } = user; // value = 'Ada'

Practical patterns

// multiple return values
function minMax(arr) {
  return [Math.min(...arr), Math.max(...arr)];
}
const [min, max] = minMax([3, 1, 4]);

// import subset
const { useState, useEffect } = React;

// iterate entries
for (const [key, value] of Object.entries(mapLike)) {
  // ...
}

Footguns

  1. const { a } = null throws — nullish source.
  2. Renames drop the original name — { name: displayName } does not declare name.
  3. Rest must be last in the pattern.
  4. Array holes and sparse arrays still position-match.
  5. Prototype properties can be picked if enumerable on the chain — rare surprise with bad objects.
// safe optional unpack
function getName(user) {
  return user?.name;
}
// or
const name = user == null ? undefined : user.name;

Interview answer

“Destructuring binds properties or elements to variables, with renames, defaults for undefined, nested patterns, and rest. I default the whole parameter to {} for options objects. Nested patterns need guards when intermediates may be missing. null does not trigger defaults.”

Mixed patterns and assignment

// already-declared variables — parentheses required for object assignment
let id, name;
({ id, name } = await getUser());

// nested array + object
const res = { rows: [{ id: 1 }, { id: 2 }] };
const {
  rows: [, second],
} = res;
second.id; // 2

// function return bag
function useToggle(init) {
  // ...
  return { on, toggle, set };
}
const { on, toggle } = useToggle(false);

Prefer named object returns over long positional tuples once you exceed two values — destructuring renames and defaults scale better for public APIs.

Further reading

Related guides