JavaScript Destructuring Table
| Pattern | What it does | Field note |
|---|---|---|
const {a, b} = obj | Object properties to variables | Names must match the keys - rename with a: newA |
const [x, y] = arr | Array items by position | Order is the name - index does not matter, position does |
const {a: renamed} = obj | Extract and rename | a: renamed reads 'a into renamed' |
const {c = 5} = obj | Default when undefined | Fires only for undefined - null passes through |
const {a, ...rest} = obj | Rest of the object | Omits a; rest is a fresh plain object |
const [first, ...others] = arr | Head and tail | The array idiom replacing slice for readability |
function f({name, age}) | Parameter destructuring | Named-argument style for APIs - the biggest readability win |
let a = 1, b = 2; [a, b] = [b, a] | Variable swap | No temp variable; needs the semicolon before the line |
const {p: {q}} = obj | Nested extraction | Throws if an intermediate level is null - optional chaining cannot help here |
Destructuring is unpacking: one statement pulls values out of objects and arrays into named variables. The table below is the working nine - the patterns that cover real code, from the basic object and array forms to the parameter destructuring that makes APIs self-documenting.
Bottom line: object patterns match KEY NAMES (const {a} = obj reads the property a), and renaming goes left-to-right - const {a: renamed} means take a, call it renamed. Array patterns match POSITION - const [x, y] takes the first two items whatever they are. Mixing the two mental models is the source of every destructuring typo.
The honest part: the default-value feature fires only for undefined - const {c = 5} = {c: null} gives c the value null, not 5. And nested patterns throw when an intermediate level is missing: const {p: {q}} = {} is a TypeError, because you cannot read q of undefined. Optional chaining cannot help inside a pattern; guard the object first.
How to use
- Match the shape: objects unpack by key name, arrays unpack by position - the left side mirrors the data's structure.
- Add defaults for undefined-prone fields, and rename when the property name is ugly or collides in scope.
- Use parameter destructuring for option objects - function f({name, age = 18}) is a named-arguments API in one line.
Frequently asked questions
How does destructuring with renaming work?
The colon means INTO: const {a: renamed} = obj takes obj.a and stores it in a variable called renamed - read the colon as into. The property name comes first because it must match the object; the variable name is yours. Swapping them is the classic typo: {renamed: a} looks for a property literally called renamed. Arrays have no names, so array patterns never need this syntax.
When do default values in destructuring apply?
Only for undefined. const {c = 5} = {c: null} leaves c as null - the property exists, so the default never fires. This matters for APIs that return explicit nulls for missing data: strip nulls first, or use the nullish pattern (c ?? 5) after destructuring. The same rule covers parameters: function f({limit = 10}) gets 10 only when limit is absent - passing {limit: undefined} still yields 10, but {limit: null} yields null.
Why does nested destructuring throw on missing objects?
Because destructuring is sugar for property access: const {p: {q}} = obj compiles to obj.p.q - if obj.p is undefined, reading q of undefined is a TypeError. Defaults guard each LEVEL separately: const {p: {q} = {}} = obj gives p an empty default, and q then reads undefined. Optional chaining cannot appear inside a pattern, so deeply-nested API responses want a guard or a default at every level that might be missing.
Is parameter destructuring just syntax sugar?
Mechanically yes - function f({name, age = 18}) unpacks the first argument - but it changes the API design: callers pass a named-options object, order stops mattering, and every option is self-documenting at the call site ({name: 'Ada', age: 36}). Two production habits: destructure with defaults for every option, and keep one non-destructured argument for required primary data (function send(to, {subject, body})) - the hybrid keeps the required part impossible to omit.