JavaScriptObject Destructuring

Object Destructuring

Destructuring is a compact syntax for pulling values out of an object into named variables. It reads like reverse object literal syntax: instead of building an object from variables, you break an object back into variables. Once you internalise it, you will see it almost everywhere modern code passes data around.

The basic form

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

const { name, age } = user;
console.log(name);   // Ada
console.log(age);    // 36

The pattern on the left mirrors the shape of the object on the right. Keys that are not mentioned are simply skipped.

Renaming on the way out

When the property name does not match the variable name you want, use key: newName. Read it as "take key and call it newName".

JS
const apiResponse = { user_id: 42, full_name: "Ada Lovelace" };

const { user_id: id, full_name: name } = apiResponse;
console.log(id, name);   // 42 'Ada Lovelace'
Default values

Add = value after a name to provide a fallback. The default only kicks in when the property is undefined — not for null, 0 or "".

JS
const { theme = "light", fontSize = 14 } = { fontSize: 18 };
console.log(theme, fontSize);   // light 18

const { value = "fallback" } = { value: null };
console.log(value);   // null — null is NOT undefined
Defaults trigger on undefined only
If you genuinely want to treat `null` as missing, combine destructuring with `??` after the fact, or test explicitly.
Renaming plus default

JS
const { theme: appTheme = "light" } = {};
console.log(appTheme);   // 'light'

Read as: "take theme (default 'light'), and call it appTheme".

Nested destructuring

The pattern can match nested shapes. Each level reuses the same syntax.

JS
const response = {
  status: 200,
  data: {
    user: { id: 42, name: "Ada" },
    pagination: { page: 1, perPage: 20 },
  },
};

const {
  data: {
    user: { id, name },
    pagination: { page },
  },
} = response;

console.log(id, name, page);   // 42 'Ada' 1
No intermediate variables
The nested pattern does *not* create variables called `data` or `user` — only the leaves (`id`, `name`, `page`). If you want both, add the parent: `const { data, data: { user } } = response`.
Destructuring function parameters

Destructuring shines in function signatures. Replace a generic options argument with a precise list of fields, and pair it with defaults to get optional named parameters.

JS
function createUser({ name, age = 18, isAdmin = false } = {}) {
  return { name, age, isAdmin };
}

console.log(createUser({ name: "Ada", age: 36 }));
// { name: 'Ada', age: 36, isAdmin: false }

console.log(createUser());
// { name: undefined, age: 18, isAdmin: false }

The = {} after the pattern is what lets you call createUser() with no argument. Without it, destructuring undefined throws.

Rest in destructuring

Use ...rest at the end of a destructuring pattern to collect the leftover properties into a new object.

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

const { id, ...publicFields } = user;
console.log(publicFields);   // { name: 'Ada', age: 36, email: 'ada@example.com' }

This is a clean way to omit a property when forwarding data — far better than delete, because it leaves the original untouched.

Destructuring an already-declared variable

Without const/let, the parser thinks the curly brace starts a block. Wrap the assignment in parentheses to disambiguate.

JS
let a, b;
({ a, b } = { a: 1, b: 2 });
console.log(a, b);   // 1 2
Common idioms in real code
  • React props: function Button({ label, onClick, disabled = false }).

  • Express handlers: app.get("/u/:id", (req, res) => { const { id } = req.params; ... }).

  • Module imports — destructuring of a namespace: const { readFile } = require("fs/promises").

  • Swapping/extracting from results: const { data, error } = await load().

One thing to remember
Destructuring is a *pattern* on the left side. Mirror the shape of the object you want to unpack, rename with `:`, default with `=`, and collect the rest with `...`.