Topics in this subject
JavaScript 3 min read Updated 5 Aug 2026

Destructuring

Unpack arrays & objects into variables — positional vs by-key, defaults, renaming, nesting, swapping, and function-param destructuring.

Destructuring unpacks values out of arrays (by position) and objects (by key) into standalone variables — less boilerplate, clearer intent.

flowchart LR
    ARR["[10, 20]"] -->|"by position"| a["const [x, y]"]
    OBJ["{ name, age }"] -->|"by key name"| b["const { name, age }"]

Array destructuring — by position#

const [a, b] = [1, 2];              // a=1, b=2
const [, , third] = [1, 2, 3];      // skip with commas → third=3
const [head, ...tail] = [1, 2, 3];  // rest → head=1, tail=[2,3]
const [x = 10] = [];                // default → x=10 (source was undefined)

// the famous swap — no temp variable
let p = 1, q = 2;
[p, q] = [q, p];                    // p=2, q=1

Object destructuring — by key#

const user = { name: "Ada", age: 30, city: "NYC" };

const { name, age } = user;             // by matching key name
const { city: town } = user;            // rename: town = "NYC"  🎯
const { role = "user" } = user;         // default when key missing
const { name: n = "Anon" } = user;      // rename + default together
const { city, ...rest } = user;         // rest → rest = { name, age }

⚠️ Rename uses key: newName — the opposite order of what many expect. { city: town } means "read city, call it town." It is not creating a city variable.

Nested destructuring#

const res = { data: { items: [{ id: 1 }] }, ok: true };
const { data: { items: [{ id }] }, ok } = res;   // id = 1, ok = true

🟢 Reach for one level or two; deeply nested destructuring gets hard to read fast.

Function parameters — the "options object" pattern 🎯#

The cleanest way to take named options with defaults:

function createUser({ name, role = "user", active = true } = {}) {
  return { name, role, active };
}
createUser({ name: "Ada" });        // { name:"Ada", role:"user", active:true }
createUser();                       // works — `= {}` lets you omit the arg entirely

Array-param destructuring works too — great with map/entries:

[[1, "a"], [2, "b"]].map(([num, char]) => `${num}${char}`);   // ["1a","2b"]
Object.entries(user).forEach(([key, val]) => console.log(key, val));

Gotchas 🎯#

const { a } = null;                 // ❌ TypeError — can't destructure null/undefined
const { a } = obj ?? {};            // ✅ guard with a fallback object

let title;
{ title } = data;                   // ❌ SyntaxError — { looks like a block
({ title } = data);                 // ✅ wrap in parens when assigning to existing vars
  • A default fires only for undefined, not null / 0 / "".
  • Destructuring copies references for nested objects (it's not a deep copy).

Interview Q&A#

Q1. Array vs object destructuring — what does each match on? Array destructuring binds by position (const [a, b] = arr), so order matters and you skip slots with commas. Object destructuring binds by key name (const { name } = obj), so order is irrelevant and missing keys yield undefined.

Q2. How do you rename a key while destructuring? Rename and default it? Use key: newName (the opposite order of what people expect), and combine with = for a default: const { name: n = "Anon" } = user; reads name, calls it n, and falls back to "Anon" if the key is undefined.

Q3. Swap two variables without a temp using destructuring.

let p = 1, q = 2;
[p, q] = [q, p];   // p=2, q=1

Q4. Why does { title } = data throw, and how do you fix it? A statement starting with { is parsed as a block, not an object pattern, so it's a SyntaxError. Wrap the assignment in parens: ({ title } = data);.

Q5. Does a destructuring default trigger for null? No — defaults fire only for undefined, not for null, 0, or "". const { role = "user" } = { role: null } leaves role as null.