Beginner0 questionsFull Guide

JavaScript Destructuring Interview Questions

Destructuring is essential modern JavaScript syntax used in every codebase. Master arrays, objects, defaults, renaming, and nested patterns.

The Mental Model

Picture unpacking a delivery box. You know the box contains specific items in a specific arrangement — a book on top, a mug in the middle, packing peanuts at the bottom. Instead of taking out everything one item at a time and setting each on a separate shelf, you reach in and place each item directly where you want it in one fluid motion. You might also skip the packing peanuts, grab just the book, and rename the shelf label to something more useful. Destructuring is that unpacking. Instead of accessing data by index or property name and assigning it to variables manually — three separate lines for three separate pieces — you declare what you want and where it goes in a single expression, mirroring the shape of the data you're unpacking. The key insight: destructuring is not a new data operation — it creates no new objects or arrays, copies no data structures. It's purely a syntax convenience for assignment. The left-hand side is a pattern that mirrors the shape of what's on the right, and JavaScript extracts the matching pieces and assigns them to your variables. The power comes from the composability: defaults, renaming, skipping, nesting, and rest can all be combined in a single expression.

The Explanation

Array destructuring — position-based extraction

const rgb = [255, 128, 0]

// Without destructuring
const red   = rgb[0]
const green = rgb[1]
const blue  = rgb[2]

// With destructuring — mirrors the array's shape on the left
const [red, green, blue] = rgb
// red = 255, green = 128, blue = 0

// Skip elements with commas
const [,, blue] = rgb              // only need blue
const [first,, third] = [1, 2, 3]  // first=1, third=3

// Rest element — captures remaining items
const [head, ...tail] = [1, 2, 3, 4, 5]
// head = 1, tail = [2, 3, 4, 5]

// Default values — used when the value is undefined
const [a = 10, b = 20, c = 30] = [1, 2]
// a = 1, b = 2, c = 30 — c was undefined so default kicks in

// Swap variables — no temp variable needed
let x = 1, y = 2
;[x, y] = [y, x]
// x = 2, y = 1

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

Object destructuring — name-based extraction

const user = { name: 'Alice', age: 30, role: 'admin', active: true }

// Basic — variable names must match property names
const { name, age } = user
// name = 'Alice', age = 30

// Rename — extract with a different variable name
const { name: userName, role: userRole } = user
// userName = 'Alice', userRole = 'admin'
// 'name' and 'role' no longer exist as variable names

// Default values — used when the property is undefined
const { name, score = 0, level = 1 } = user
// score = 0 (not in user), level = 1 (not in user), name = 'Alice'

// Rename AND default together
const { displayName: name = 'Anonymous' } = user
// user has no 'displayName', so name = 'Anonymous'

// Rest — collect remaining properties
const { name, age, ...rest } = user
// rest = { role: 'admin', active: true }

// Picking specific properties from an object
const { name, role } = user  // only extract what you need

Nested destructuring — matching deep structures

const response = {
  status: 200,
  data: {
    user: {
      id: 1,
      name: 'Alice',
      address: {
        city: 'Paris',
        country: 'France'
      }
    },
    permissions: ['read', 'write']
  }
}

// Nested object destructuring
const {
  status,
  data: {
    user: {
      name,
      address: { city, country }
    },
    permissions: [firstPermission, ...otherPermissions]
  }
} = response

// status = 200, name = 'Alice', city = 'Paris', country = 'France'
// firstPermission = 'read', otherPermissions = ['write']

// Note: 'data', 'user', 'address', 'permissions' are NOT created as variables
// They are patterns used to navigate — only the leaf variable names exist

Destructuring in function parameters

// The most important real-world use of destructuring

// Without destructuring — positional, hard to read with many args
function createUser(name, age, role, active, score) { }
createUser('Alice', 30, 'admin', true, 95)  // what is 'true'? what is 95?

// With destructuring — named, self-documenting, order irrelevant
function createUser({ name, age, role = 'user', active = true, score = 0 }) {
  return { name, age, role, active, score }
}
createUser({ name: 'Alice', age: 30, role: 'admin', score: 95 })
// Default for 'active' and partial score — clear what's being passed

// Rename in parameters
function display({ name: displayName, role: userRole = 'guest' }) {
  console.log(`${displayName} (${userRole})`)
}

// Array params
function first([head]) { return head }
function swap([a, b]) { return [b, a] }

// Nested in params
function getCity({ address: { city = 'Unknown' } = {} }) {
  return city
}
getCity({ address: { city: 'Paris' } })  // 'Paris'
getCity({ address: {} })                  // 'Unknown'
getCity({})                               // 'Unknown' — address defaults to {}

// React component props — the canonical use
function UserCard({ name, avatar, role = 'user', onEdit }) {
  return (
    <div>
      <img src={avatar} alt={name} />
      <h2>{name}</h2>
      <span>{role}</span>
      <button onClick={onEdit}>Edit</button>
    </div>
  )
}

Destructuring in loops

const users = [
  { id: 1, name: 'Alice', score: 90 },
  { id: 2, name: 'Bob',   score: 75 },
  { id: 3, name: 'Carol', score: 85 },
]

// for...of with object destructuring
for (const { id, name, score } of users) {
  console.log(`${id}: ${name} scored ${score}`)
}

// Object.entries() — [key, value] pairs
const config = { host: 'localhost', port: 3000, debug: true }
for (const [key, value] of Object.entries(config)) {
  console.log(`${key} = ${value}`)
}

// map with destructuring
const labels = users.map(({ name, score }) => `${name}: ${score}`)
// ['Alice: 90', 'Bob: 75', 'Carol: 85']

// filter then destructure in the callback
const topScorers = users
  .filter(({ score }) => score >= 85)
  .map(({ name }) => name)
// ['Alice', 'Carol']

Import destructuring — the module connection

// ES modules use object destructuring syntax for named imports
import { useState, useEffect, useCallback } from 'react'
import { BrowserRouter, Route, Switch } from 'react-router-dom'

// It's not EXACTLY the same as destructuring (imports are live bindings)
// but the mental model is identical — pull out named exports by name

// Dynamic import with destructuring
const { default: lodash, cloneDeep } = await import('lodash')

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

Gotchas and edge cases

// Gotcha 1: destructuring undefined/null throws
const { name } = null       // TypeError: Cannot destructure 'name' of null
const { name } = undefined  // TypeError

// Fix: provide a default for the whole value
const { name } = user ?? {}  // safe — {} if user is null/undefined
const { name } = user || {}  // also works but || triggers on any falsy value

// Gotcha 2: object destructuring in a statement (not assignment)
let name, age
{ name, age } = user  // SyntaxError — {} starts a block statement

// Fix: wrap in parentheses
;({ name, age } = user)  // ✓

// Gotcha 3: nested destructuring with potentially missing intermediaries
const { address: { city } } = user  // throws if user.address is undefined

// Fix: default the intermediate
const { address: { city } = {} } = user  // safe — address defaults to {}

// Gotcha 4: default only triggers for undefined, not null
const { name = 'Anonymous' } = { name: null }
// name = null — null does NOT trigger the default
// Only undefined does

Common Misconceptions

⚠️

Many devs think destructuring copies or clones the values — but actually destructuring is purely assignment syntax. It binds variable names to the same values (and same object references) that were in the source. Mutating a destructured object property still mutates the original, because the variable holds the same reference.

⚠️

Many devs think default values in destructuring trigger on null — but actually defaults only trigger when the value is strictly undefined. A property that is explicitly set to null, 0, false, or empty string will use that null/falsy value, not the default. This distinction is important when working with APIs that use null to mean "intentionally absent."

⚠️

Many devs think the intermediate property names in nested destructuring create variables — but actually in const { address: { city } } = user, only city is created as a variable. address is a navigation path, not a variable name. If you need both the nested value and the intermediate object, you must destructure them in separate steps or use comma separation.

⚠️

Many devs think object destructuring requires the source to have all the listed properties — but actually if a property doesn't exist on the source, the variable gets undefined (or the default value if one is provided). Destructuring is forgiving — it's only a problem if you try to further destructure an undefined intermediate property.

⚠️

Many devs think array and object destructuring can be freely mixed — and they can, but the syntax must match the data type precisely. Arrays are destructured with [], objects with {}. Trying to array-destructure an object (const [a, b] = { a: 1, b: 2 }) doesn't extract properties — it tries to iterate the object, which fails unless it's iterable.

⚠️

Many devs think destructuring in function parameters is just a style preference — but actually it fundamentally changes the function's API: named parameters are order-independent, self-documenting at the call site, and allow providing defaults for individual fields. The difference between createUser('Alice', 30) and createUser({ name: 'Alice', age: 30 }) is a significant API design choice, not cosmetic.

Where You'll See This in Real Code

React's useState, useReducer, and custom hooks all return arrays specifically to enable destructuring with caller-chosen variable names — const [count, setCount] = useState(0). If useState returned an object, you'd have to use the framework's chosen property names or alias them. The array return enables const [isOpen, setIsOpen] = useState(false) alongside const [count, setCount] = useState(0) without naming conflicts.

GraphQL query results and REST API responses are almost always destructured in React components — const { data: { users }, loading, error } = useQuery(GET_USERS) is standard Apollo Client code. Nested destructuring maps directly to the nested JSON shape of the response, making the code read as a description of the data structure.

Express.js route handlers routinely destructure req — const { params: { id }, body: { name, email }, query: { page = 1 } } = req — extracting only the needed fields from the request object. This pattern makes it immediately clear at the top of each handler what data the route consumes, without reading through lines of req.body.name, req.query.page.

Vue 3 Composition API's setup() function returns an object with all the reactive state and methods the template needs, and component authors destructure it with toRefs to preserve reactivity — const { name, age } = toRefs(props). Understanding that naive destructuring of reactive objects breaks the reactive binding is a Vue-specific consequence of how destructuring works at the reference level.

TypeScript narrows types through destructuring in a way that makes complex union type handling cleaner — destructuring a discriminated union const { type, payload } = action and then switching on type gives TypeScript enough information to narrow payload to the correct type in each branch. This is the foundation of Redux action typing in TypeScript.

Webpack's tree shaking works more effectively with named exports consumed via import destructuring — import { throttle } from 'lodash-es' allows bundlers to detect that only throttle is used and exclude everything else. This is why lodash-es was created (named ES module exports), and why import { something } from 'library' is preferable to import library from 'library' for bundle-size optimization.

Interview Cheat Sheet

  • Array destructuring: position-based — [a, b, c] = [1, 2, 3]
  • Object destructuring: name-based — { name, age } = user
  • Skip elements: [,, third] — commas mark skipped positions
  • Rename: { name: userName } — extract name, call it userName
  • Default: { score = 0 } — only triggers on undefined, not null
  • Rest: [...tail] or { ...rest } — collects remaining into array/object
  • Nested: { address: { city } } — city is a variable, address is a path
  • Defaults trigger only on undefined — null, 0, false do NOT trigger defaults
  • In function params: enables named arguments with defaults, order-independent
  • Intermediate paths in nested destructuring are NOT variables
  • Destructuring null/undefined throws — guard with ?? {} or default the whole value
💡

How to Answer in an Interview

  • 1.Walk through the rename syntax carefully — { name: userName } reads backwards at first
  • 2.The null-vs-undefined default distinction is a trap question — state it explicitly
  • 3.The swap idiom [x, y] = [y, x] shows you know practical uses beyond basics
  • 4.The nested default gotcha { address: { city } = {} } is a real production pattern
  • 5.Connecting to React's useState API design choice shows you understand why APIs are shaped the way they are
  • 6.Live coding: destructure a deeply nested API response in one expression — shows fluency
📖 Deep Dive Articles
Modern JavaScript: ES6+ Features Every Developer Must Know13 min read

Practice Questions

No questions tagged to this topic yet.

Tag questions in Admin → Questions by setting the "Topic Page" field to javascript-destructuring-interview-questions.

Related Topics

JavaScript Array Interview Questions
Intermediate·8–12 Qs
JavaScript Spread & Rest Operator Interview Questions
Beginner·3–5 Qs
🎯

Can you answer these under pressure?

Reading answers is not the same as knowing them. Practice saying them out loud with AI feedback — that's what builds real interview confidence.

Practice Free →Try Output Quiz