Skip to content
JavaScript js arrays 4 min read

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 or Set. 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

PatternMeaning
const [a, b] = arrBind first two elements
const [a = 1] = arrDefault when element is undefined
const [, , c] = arrSkip elements with holes
const [a, ...rest] = arrCollect 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 undefined afterward.
  • Use holes to skip values rather than declaring unused variables.
  • Put ...rest last 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 useState pattern.
Last updated June 1, 2026
Was this helpful?