Array Destructuring
Array destructuring (ES2015) is a concise syntax for pulling values out of an array and binding them to individual variables in a single statement. Instead of reading elements one index at a time, you write a pattern on the left side of an assignment that mirrors the array’s shape. It works in const/let declarations, plain assignments, function parameters, and for...of loops — making it one of the most reached-for features in everyday JavaScript. This page covers the basics, defaults, skipping, swapping, the rest pattern, and use in function signatures.
The basics
Wrap a comma-separated list of variable names in square brackets on the left-hand side. Each name binds to the element at the matching position. If there are fewer names than elements, the extras are simply ignored; if there are more names than elements, the surplus names become undefined.
const colors = ["red", "green", "blue"];
const [first, second] = colors;
console.log(first, second);
const [a, b, c, d] = colors;
console.log(d);
Output:
red green
undefined
Destructuring is positional, so it works on any iterable, not just arrays — strings, Sets, and the result of Map.entries() all destructure cleanly.
const [x, y] = "hi";
console.log(x, y); // h i
Default values
Any binding can declare a fallback with =. The default is used only when the matched element is undefined — a null, 0, or empty string is left untouched, since those are real values.
const [host = "localhost", port = 8080] = ["example.com"];
console.log(host, port);
const [open = true, closed = true] = [false, undefined];
console.log(open, closed);
Output:
example.com 8080
false true
Defaults are evaluated lazily and can reference earlier bindings, which is handy for derived fallbacks.
const [width = 100, height = width] = [200];
console.log(width, height); // 200 200
Skipping elements
Leave a “hole” — an empty slot between commas — to ignore a position you don’t need. This keeps the rest of the pattern aligned without inventing throwaway variable names.
const rgba = [255, 128, 0, 0.5];
const [red, , , alpha] = rgba;
console.log(red, alpha);
Output:
255 0.5
Swapping variables
A classic use is swapping two values without a temporary variable. The right side is fully evaluated into an array first, then destructured back into the targets, so the order is safe.
let a = 1;
let b = 2;
[a, b] = [b, a];
console.log(a, b);
Output:
2 1
The same trick rotates three or more values in one line: [a, b, c] = [c, a, b].
The rest pattern
A trailing ...name collects every remaining element into a new array. Unlike skipping, the rest captures the tail rather than discarding it. It must come last — a rest element followed by anything is a syntax error.
const [head, ...tail] = [1, 2, 3, 4, 5];
console.log(head);
console.log(tail);
Output:
1
[ 2, 3, 4, 5 ]
If there are no remaining elements, the rest binds to an empty array (never undefined), which makes it safe to map or spread without a guard.
const [only, ...nothing] = ["solo"];
console.log(nothing); // []
The rest pattern always produces a genuine
Array, even when the source is a string orSet. That is a quick way to convert an iterable’s tail into an array for further array methods.
In function parameters
Destructuring shines in parameter lists: a function can declare exactly which positions it needs, with defaults, right in the signature. This is common when consuming tuple-like returns or coordinate pairs.
function distance([x1, y1], [x2, y2]) {
return Math.hypot(x2 - x1, y2 - y1);
}
console.log(distance([0, 0], [3, 4]));
Output:
5
It pairs naturally with for...of over entries, where each element is a [key, value] pair:
const scores = new Map([["ada", 90], ["alan", 85]]);
for (const [name, score] of scores) {
console.log(`${name}: ${score}`);
}
Output:
ada: 90
alan: 85
From function returns
Functions can only return one value, but returning a small array and destructuring it gives you ergonomic “multiple returns.” React’s useState hook is the most famous example of this [value, setter] convention.
function minMax(nums) {
return [Math.min(...nums), Math.max(...nums)];
}
const [low, high] = minMax([7, 2, 9, 4]);
console.log(low, high);
Output:
2 9
Pattern reference
| Pattern | Meaning |
|---|---|
const [a, b] = arr | Bind first two elements |
const [a = 1] = arr | Default when element is undefined |
const [, , c] = arr | Skip elements with holes |
const [a, ...rest] = arr | Collect the tail into an array |
[a, b] = [b, a] | Swap without a temp variable |
function f([x, y]) {} | Destructure a parameter |
Best Practices
- Use destructuring for clear, positional unpacking; reach for object destructuring when order is irrelevant and names matter.
- Provide defaults for optional positions instead of checking for
undefinedafterward. - Use holes to skip values rather than declaring unused variables.
- Put
...restlast and rely on it returning[]so downstream array methods are always safe. - Prefer the
[a, b] = [b, a]swap over a manual temporary variable. - Wrap a standalone destructuring assignment’s right side or the whole statement carefully — a line starting with
[after an unterminated previous line can be parsed as indexing, so keep semicolons consistent. - Return small tuples and destructure them for readable multiple-return functions, mirroring the
useStatepattern.