Destructuring Is Pattern Matching on Shapes
Destructuring lets you write a pattern that mirrors the shape of an object or array, and Python-style pull values out by name or position in a single line. Instead of reaching into a value property by property, you describe what you want and JavaScript hands it over.
The two flavours:
The curly braces match an object by property name. The square brackets match an array by position. In both cases, the variables on the left are new declarations — you're not indexing into the value, you're describing a pattern that extracts the pieces.
Before destructuring existed, the same code looked like this:
const name = user.name;
const age = user.age;
const first = scores[0];
const second = scores[1];
Not the end of the world, but repetitive once you're doing it on every function.
Object Destructuring Uses Property Names
For objects, the names inside the braces must match property names on the source. Order doesn't matter — JavaScript looks them up by key.
If a property doesn't exist on the object, the variable is undefined — no error:
That silent-undefined behavior is important to remember when a typo in a property name leaves you scratching your head at 2am.
Renaming Variables
Sometimes the property name on the object isn't what you want the variable to be called — maybe it clashes with something else in scope, or the API uses a naming convention you don't love. Use original: newName to rebind:
Read it as "take the id property, call it userId." The property name comes first, the new variable name after the colon. It looks like a type annotation from other languages — it isn't.
Default Values
If a property might be missing, give it a default right in the pattern:
Defaults only kick in when the value is undefined. null, 0, and "" all pass through unchanged:
That one catches people. If you want null to trigger the default too, you need an explicit check — or use the nullish coalescing operator ?? after destructuring.
You can stack defaults with renaming:
Array Destructuring Uses Position
Arrays don't have names, just indices, so the pattern matches by position. Use commas to skip entries you don't care about:
The two leading commas say "skip index 0 and 1." A bit dense visually, but handy when you only want one value from the middle.
Array destructuring shines with functions that return tuples:
Same pattern shows up everywhere in React hooks: const [count, setCount] = useState(0).
Rest Patterns: Collecting the Leftovers
Inside a destructuring pattern, ...name collects everything that wasn't matched by name or position into a new variable.
For arrays, rest grabs the tail:
For objects, rest grabs every property that wasn't explicitly named:
This is the idiomatic way to strip one field off an object without mutating it — rest is a new object containing everything except id.
Rest must be the last element in the pattern. const [...init, last] is a syntax error.
Nested Destructuring
Patterns nest. If a property is itself an object or array, you can destructure into it in the same expression:
Powerful, but lean on it carefully. Three levels of nested braces start to feel like a puzzle. When it does, pull intermediate values into their own variables — readability beats cleverness.
One gotcha: data: { user } in the pattern does not create a variable called data. It's a directive saying "descend into data and keep destructuring." If you need data itself, add it separately:
Destructuring Function Parameters
The most common place you'll destructure is in a function's parameter list. It turns "pass an options object" into a signature that documents itself:
At the call site, it looks like any other options-object call. Inside the function, you get named variables with defaults — no more options.name || "default" boilerplate.
One sharp edge: calling this function with no argument crashes, because you can't destructure undefined. Give the whole parameter a default:
The = {} after the pattern says "if no argument comes in, pretend it was an empty object." Then the inner defaults take over.
Swapping and Reassigning
Destructuring works with already-declared variables too, but you need parentheses around the object pattern (otherwise JavaScript reads the { as the start of a block):
The array swap is clean. The object reassignment is rarer, but the parentheses trick is worth filing away for when you need it.
A Realistic Example
Combining most of what's above — a function that processes an API response:
Every destructured layer has a default, so the function survives partial data without a pile of if guards. That's the real payoff: signatures that are both precise and forgiving.
Next: Object Spread
Destructuring pulls values out of objects. Spread puts them in — copying, merging, and overriding. The two are constant companions in modern JavaScript, and spread is next.
Frequently Asked Questions
What is destructuring in JavaScript?
Destructuring is a syntax for pulling values out of objects or arrays and binding them to variables in one step. const { name } = user; grabs the name property off user. const [first, second] = list; grabs the first two elements of list. It's a pattern on the left side of = that mirrors the shape of the value on the right.
How do you rename a variable when destructuring?
Use the { original: newName } syntax. const { name: username } = user; pulls the name property off user and binds it to a local variable called username. It's easy to misread as type annotation — remember the property name comes first, then the new variable name after the colon.
Can you set default values with destructuring?
Yes. const { timeout = 5000 } = options; uses 5000 if options.timeout is undefined. Defaults only apply to undefined — null, 0, and '' pass through unchanged. You can combine defaults with renaming: const { t: timeout = 5000 } = options;.
What's the difference between destructuring and spread?
They look similar but do opposite things. Destructuring (const { a, b } = obj) pulls values out of a structure. Spread (const copy = { ...obj }) puts values into a new structure. The ... inside a destructuring pattern is a rest pattern — it collects the leftovers into a new variable.