Skip to content
JavaScript js objects 4 min read

Object Destructuring

Object destructuring is an ES2015 syntax that unpacks properties from an object into distinct variables in a single, readable statement. Instead of repeatedly writing config.host, config.port, and so on, you name the properties you care about once and let the language wire them up. It is one of the most-used features in modern JavaScript, especially for working with function arguments, API responses, and module imports.

Basic destructuring

You destructure an object by placing a pattern that looks like an object literal on the left-hand side of an assignment. Each name inside the braces matches a property of the same name on the source object, and a variable with that name is created.

const user = { name: "Ada", role: "engineer", id: 42 };

const { name, role } = user;

console.log(name);
console.log(role);

Output:

Ada
engineer

The order of names does not matter — properties are matched by key, not by position (unlike array destructuring). Any property you do not list is simply ignored.

Renaming variables

Sometimes the property key is not the variable name you want, perhaps because it clashes with an existing variable or is not descriptive enough. Use the key: newName syntax to bind a property to a differently named variable.

const response = { id: 7, msg: "ok" };

const { id: statusId, msg: message } = response;

console.log(statusId);
console.log(message);

Output:

7
ok

Here id and msg no longer exist as variables — only statusId and message do.

Default values

If a property is missing (its value is undefined), you can supply a fallback with =. Defaults guard against gaps in incoming data and remove the need for manual || checks.

const settings = { theme: "dark" };

const { theme = "light", fontSize = 14 } = settings;

console.log(theme);
console.log(fontSize);

Output:

dark
14

A default kicks in only when the value is strictly undefined. If a property exists but is null, 0, or "", the default is not applied — those are real values.

Defaults combine cleanly with renaming. The default goes after the new name:

const { msg: message = "no message" } = {};

console.log(message);

Output:

no message

Nested destructuring

Objects often contain other objects. You can mirror that structure in the pattern to reach deeply nested values without intermediate variables.

const profile = {
  name: "Ada",
  address: {
    city: "London",
    geo: { lat: 51.5, lng: -0.12 },
  },
};

const {
  address: {
    city,
    geo: { lat },
  },
} = profile;

console.log(city);
console.log(lat);

Output:

London
51.5

Note that address and geo are not created as variables here — they are only paths used to reach city and lat. If a nested object might be missing, pair destructuring with optional chaining when reading, or give the nested level a default object: const { address: { city } = {} } = profile;.

Destructuring in function parameters

The most impactful use of destructuring is in function signatures. Instead of accepting an opaque options object and digging into it, you declare exactly which fields the function needs, complete with defaults. This makes call sites self-documenting and order-independent.

function createButton({ label, type = "button", disabled = false } = {}) {
  return `<button type="${type}"${disabled ? " disabled" : ""}>${label}</button>`;
}

console.log(createButton({ label: "Save" }));
console.log(createButton({ label: "Delete", disabled: true }));
console.log(createButton());

Output:

<button type="button">Save</button>
<button type="button" disabled>Delete</button>
<button type="button">undefined</button>

The trailing = {} on the parameter is important: it lets the function be called with no arguments at all. Without it, createButton() would throw because you cannot destructure undefined.

Syntax reference

PatternMeaning
const { a } = objBind a to obj.a
const { a: x } = objBind x to obj.a (rename)
const { a = 1 } = objDefault a to 1 if undefined
const { a: x = 1 } = objRename to x, default 1
const { a: { b } } = objReach nested obj.a.b as b
const { a, ...rest } = objCollect remaining keys into rest

The last row uses rest properties — covered in depth in Spread and rest with objects.

Assigning to existing variables (without const/let) requires wrapping the pattern in parentheses: ({ a, b } = obj);. The leading { would otherwise be parsed as a block statement.

Best practices

  • Prefer destructuring in function parameters for any function taking 3+ options — it documents the contract at a glance.
  • Always supply = {} as the parameter default so the function can be called with no arguments.
  • Use defaults instead of value || fallback to avoid clobbering valid falsy values like 0 or "".
  • Keep nesting shallow; deeply nested patterns hurt readability. Destructure one level, then again on the next line if needed.
  • Combine renaming with defaults when integrating external APIs whose keys are inconsistent or terse.
  • Reach for optional chaining or nested defaults when a nested object may be absent, to avoid runtime errors.
Last updated June 1, 2026
Was this helpful?