Array Destructuring
Array destructuring is a piece of ES2015 syntax that lets you pull elements out of an array (or any iterable) and bind them to variables in one statement. It is one of those features that looks like sugar and quickly becomes essential — once you start writing const [a, b] = pair, pair[0] / pair[1] feels clumsy.
The basics
Use square brackets on the left of an assignment. The pattern is matched against the array on the right; each name in the pattern receives the element at the same position.
const colors = ["red", "green", "blue"]; const [first, second, third] = colors; // first = "red", second = "green", third = "blue" // Skip elements with a hole const [, , onlyThird] = colors; // onlyThird = "blue" // Fewer names than elements — the rest are ignored const [a] = colors; // a = "red" // More names than elements — extras are undefined const [x, y, z, w] = ["one", "two"]; // w = undefined
Default values
If an element is missing or undefined, the default kicks in. null does not trigger the default — only undefined.
const [a = 1, b = 2, c = 3] = [10, undefined]; // a = 10, b = 2 (default fired), c = 3 (missing) const [x = "hi"] = [null]; // x = null — null is a real value, not "missing"
The swap idiom
Swapping two variables without a temporary is the canonical example: it reads exactly like its meaning.
let a = 1; let b = 2; [a, b] = [b, a]; console.log(a, b); // 2 1
2 1
Nested destructuring
Patterns nest. You can pull elements out of arrays-of-arrays and even mix in object destructuring.
const point = [10, [20, 30]];
const [x, [y, z]] = point;
// x = 10, y = 20, z = 30
// Mixing with objects
const users = [
{ name: "Ada", roles: ["admin", "editor"] },
{ name: "Lin", roles: ["viewer"] },
];
const [{ name: firstName, roles: [primaryRole] }] = users;
// firstName = "Ada", primaryRole = "admin"Rest in destructuring
A trailing ...rest pattern collects everything that was not destructured into a new array. It must be the last element in the pattern.
const [head, ...tail] = [1, 2, 3, 4, 5]; // head = 1, tail = [2, 3, 4, 5] const [, ...withoutFirst] = ["a", "b", "c"]; // withoutFirst = ["b", "c"] // SyntaxError — rest must be last // const [...rest, last] = [1, 2, 3];
Works on any iterable
Array destructuring is really iterable destructuring. Strings, Map, Set, generators — anything with a [Symbol.iterator] works.
const [first, second] = "hi";
// first = "h", second = "i"
const m = new Map([["a", 1], ["b", 2]]);
for (const [key, value] of m) {
console.log(key, value);
}
// Generators
function* counter() { yield 10; yield 20; yield 30; }
const [a, b] = counter();
// a = 10, b = 20Destructuring in function parameters
You can destructure right in a parameter list. It is especially handy with callbacks that pass arrays — Map.entries, Object.entries, .map((item, i) => ...).
const pairs = [["a", 1], ["b", 2], ["c", 3]];
pairs.forEach(([key, value]) => {
console.log(key, "=", value);
});
// With a default for the whole parameter
function greet([first = "there", last = ""] = []) {
return `Hello, ${first} ${last}`.trim();
}
greet(["Ada", "Lovelace"]); // "Hello, Ada Lovelace"
greet(); // "Hello, there"Common pitfalls
Destructuring
nullorundefinedthrows —const [a] = nullis a TypeError. Pair with a fallbackconst [a] = arr ?? [].Skipped slots still consume positions —
[, b]means "skip first, take second", not "take first under the name b".Default values are evaluated lazily —
const [a = expensive()] = [1]does not callexpensivebecauseawas provided.A trailing comma in a pattern does not change anything —
[a, b,]is the same as[a, b].
The next page looks at the closely related ... spread operator and how it powers cloning, merging and rest-arguments in array contexts.