JavaScript Destructuring: Unpacking Arrays and Objects Cleanly

Destructuring lets you pull values out of arrays and objects into variables in a single, readable line. Learn array and object destructuring, defaults, renaming, nesting, and the patterns you'll use in real code every day.

Published August 3, 202610 min readBy ACY Partner Indonesia
JavaScript destructuring — unpacking arrays and objects into variables
300 × 250Ad Space AvailablePlace your ad here

By now you’ve spent plenty of time pulling values out of arrays and objects the long way — one line per value, reaching in by index or by key. It works, but it gets repetitive fast. Destructuring is the modern shortcut: a piece of syntax (added in ES2015) that unpacks values out of arrays and objects straight into variables, often in a single line. Once it clicks, you’ll reach for it constantly — and you’ll start seeing it everywhere in other people’s code, from React components to Node.js modules.

This article assumes you’re comfortable with the array and object basics. If user.name and fruits[0] still feel shaky, give that earlier article another read first — destructuring is just a faster way to do exactly that.

What destructuring actually does

Destructuring is a way of writing an assignment where the left side mirrors the shape of the data on the right. Instead of describing one value at a time, you describe a pattern, and JavaScript fills in the matching pieces.

Here’s the old way of grabbing a few values out of an object:

const user = { name: "John Doe", age: 28, city: "Jakarta" };

const name = user.name;
const age = user.age;
const city = user.city;

Three lines, all saying basically the same thing. With destructuring, that collapses into one:

const user = { name: "John Doe", age: 28, city: "Jakarta" };

const { name, age, city } = user;

console.log(name);   // "John Doe"
console.log(age);    // 28
console.log(city);   // "Jakarta"

The curly braces on the left aren’t creating an object — they’re a pattern. JavaScript reads “find the name, age, and city properties on the right-hand object, and create local variables with those same names.” Same result, a quarter of the typing.

Array destructuring

Let’s start with arrays, since the rule there is simple: variables match up by position. You write square brackets on the left, list out variable names, and they get filled from the array in order.

const colors = ["red", "green", "blue"];

const [first, second, third] = colors;

console.log(first);    // "red"
console.log(second);   // "green"
console.log(third);    // "blue"

The variable names are entirely up to you — first, second, third here, but they could be anything. What matters is the order: the first name catches the first item, and so on down the line.

Skipping items

You don’t have to take every element. Leave a slot empty (with just a comma) to skip the item at that position:

const scores = [90, 85, 70, 60];

const [top, , third] = scores;

console.log(top);     // 90
console.log(third);   // 70

That empty slot between the commas tells JavaScript “skip index 1, I don’t want it.” Handy when you only care about a couple of items out of a longer list.

Swapping variables

Here’s a neat trick that array destructuring makes almost magical. Swapping two variables used to need a temporary third variable. Now it’s one line:

let a = 1;
let b = 2;

[a, b] = [b, a];

console.log(a);   // 2
console.log(b);   // 1

The right side builds a quick array [2, 1], and the left side immediately unpacks it back into a and b — swapped. Clean and no temp variable in sight.

Arrays match by position, objects match by name

This is the one distinction to keep straight. Array destructuring uses [ ] and fills variables in order — the name you pick is yours to choose. Object destructuring uses { } and fills variables by property name — your variable name must match the property’s key (unless you rename it, which we’ll get to). Order doesn’t matter for objects; the key does.

Object destructuring

Objects are where destructuring really earns its keep, because real-world data is mostly objects. As we saw, you use curly braces and the variable names must match the property names:

const product = {
  title: "Wireless Keyboard",
  price: 250000,
  inStock: true,
};

const { title, price, inStock } = product;

console.log(title);     // "Wireless Keyboard"
console.log(price);     // 250000
console.log(inStock);   // true

Because matching is by name rather than position, you can list the properties in any order you like, and you can pick out only the ones you need — there’s no obligation to pull every property.

Renaming while you destructure

Sometimes the property name isn’t the variable name you want — maybe it’s too generic, or it clashes with an existing variable. You can rename on the spot with a colon:

const response = { id: 42, n: "Jane Doe" };

const { id: userId, n: userName } = response;

console.log(userId);     // 42
console.log(userName);   // "Jane Doe"

Read it as “take the id property and call it userId.” The syntax looks a little backwards at first (oldName: newName), but it’s consistent with how object literals are written.

Renaming is a colon, not a regular assignment

The colon inside a destructuring pattern means “rename,” not “assign a value.” So const { id: userId } = response does not look up a variable called userId — it creates one, filled from response.id. People sometimes confuse this with setting a default value, which uses an equals sign (=) instead. Keep them separate: : renames, = provides a fallback.

Default values

If a property might be missing, destructuring would normally hand you undefined. You can supply a fallback with =, and it kicks in only when the value is missing:

const settings = { theme: "dark" };

const { theme, fontSize = 16 } = settings;

console.log(theme);      // "dark"
console.log(fontSize);   // 16  (settings.fontSize was missing, so the default applied)

There’s one subtlety worth knowing: the default fires only when the value is undefined — not when it’s null, 0, false, or an empty string. Those are real values, so they’re kept as-is.

const config = { count: 0, label: null };

const { count = 10, label = "none" } = config;

console.log(count);   // 0     (0 is a real value — default ignored)
console.log(label);   // null  (null is a real value — default ignored)

That distinction trips people up. If you genuinely want a fallback for null too, you’ll need an explicit check rather than relying on the default.

Combining rename and default

You can rename and set a default at the same time. The order is rename first, then default:

const user = {};

const { name: fullName = "Guest" } = user;

console.log(fullName);   // "Guest"

Here user has no name property, so the default "Guest" is used, and it lands in a variable called fullName. It reads as “take name, call it fullName, and if it’s missing, use 'Guest'.”

Nested destructuring

Real data nests — objects inside objects, arrays inside objects. Destructuring can dig into those layers in one go by mirroring the nested shape:

const order = {
  customer: { name: "John Doe", email: "john@example.com" },
  total: 490000,
};

const { customer: { name, email }, total } = order;

console.log(name);    // "John Doe"
console.log(email);   // "john@example.com"
console.log(total);   // 490000

The pattern follows the structure: to reach into customer, you write customer: { ... } and list the inner properties you want. Notice that customer itself does not become a variable here — it’s only acting as a path to drill through. If you also want customer as a variable, you’d destructure it on its own line.

Don't over-nest

Nested destructuring is handy, but a deeply nested pattern can become harder to read than the boring order.customer.name version it replaces. If you find yourself three or four levels deep in braces, it’s often clearer to pull out the inner object first, then destructure that on the next line. Readability beats cleverness — write the version a teammate can scan in a second.

Destructuring in function parameters

This is where destructuring becomes genuinely powerful, and it’s probably the pattern you’ll use most. Instead of accepting a whole object and then pulling fields out inside the function, you can destructure right in the parameter list. If you’ve read the functions article, this builds straight on that.

function greet({ name, role }) {
  console.log(`Hi ${name}, you're a ${role}.`);
}

const employee = { name: "Jane Doe", role: "Designer", id: 7 };

greet(employee);   // "Hi Jane Doe, you're a Designer."

The function asks for exactly the two fields it needs — name and role — and ignores the rest. This is a hugely common way to write functions that take an “options object,” because the call site stays readable and the function signature documents what it actually uses.

You can layer defaults in here too, which makes for clean configurable functions:

function createButton({ label = "Click me", color = "blue" } = {}) {
  console.log(`Button: ${label} (${color})`);
}

createButton({ label: "Save" });   // "Button: Save (blue)"
createButton();                    // "Button: Click me (blue)"

That trailing = {} on the parameter is the small but important part: it means “if no argument is passed at all, default to an empty object.” Without it, calling createButton() with nothing would throw, because you can’t destructure undefined.

You can't destructure null or undefined

Trying to destructure null or undefined throws a TypeError — for example const { x } = null crashes immediately. This bites most often with function parameters and with data that might not have arrived yet (a missing API field, an empty response). Two common guards: give the parameter a default like = {} so there’s always an object to unpack, or destructure from a fallback such as const { x } = data || {}. Either way, make sure there’s a real object on the right before you reach into it.

Destructuring in loops

Destructuring pairs beautifully with the loops you already know. When you iterate over an array of objects — the most common real-world data shape — you can unpack each item right in the loop header. If loops are fresh in your memory, this slots right in:

const team = [
  { name: "John Doe", role: "Developer" },
  { name: "Jane Doe", role: "Designer" },
];

for (const { name, role } of team) {
  console.log(`${name} — ${role}`);
}
// "John Doe — Developer"
// "Jane Doe — Designer"

The { name, role } in the for...of header destructures each object as the loop visits it, so inside the body you work with clean, named variables instead of team[i].name. It reads almost like plain English.

Wrapping up

Destructuring is one of those features that feels like a small convenience and then quietly changes how you write JavaScript. Here’s the shape of it:

  • Destructuring unpacks values from arrays and objects into variables, with a pattern on the left that mirrors the data on the right.
  • Array destructuring uses [ ] and matches by position. You can skip items with an empty slot and swap variables in one line.
  • Object destructuring uses { } and matches by property name. Your variable name must match the key — unless you rename it with a colon ({ key: newName }).
  • Defaults with = fill in missing values, but only when the value is undefined — not for null, 0, false, or "".
  • It nests to reach into deeper structures, shines in function parameters (especially “options objects” with = {} as a guard), and reads cleanly inside for...of loops.
  • You cannot destructure null or undefined — always make sure there’s an object on the right.

Destructuring also pairs naturally with its sibling syntax, the spread and rest operators — the ... you may have already spotted in modern code. That’s the next article, and together with destructuring it forms the toolkit you’ll use to move data around cleanly in nearly every modern JavaScript project.

Tags:javascriptfrontenddestructuringes6intermediate
728 × 90Ad Space AvailablePlace your ad here

Related Articles

See All Articles

You Might Also Like

Frontend best practices overview cover
Frontend / Fundamentals

Frontend Best Practices: An Overview

A friendly map of what good frontend really means — semantic HTML, clean CSS, unobtrusive JavaScript, responsive layouts, performance, and progressive enhancement, with pointers to go deeper.

Sep 20, 20268 min read
A Frontend Developer Roadmap cover with the path HTML to CSS to JavaScript
Frontend / Fundamentals

A Frontend Developer Roadmap: What to Learn, and in What Order

A calm, step-by-step learning path for beginners: HTML, CSS, JavaScript, developer tools, responsive and accessible design, a framework, TypeScript, and deployment, with the reasoning behind each step.

Sep 20, 202611 min read
Title card reading Styling and Interactivity over a dark blue ACY Partner background
Frontend / Fundamentals

How Styling and Interactivity Work

A beginner-friendly look at how CSS turns plain HTML into a designed layout, and how JavaScript adds behavior — the structure, style, behavior mental model for building web pages.

Sep 20, 20269 min read
Three front-end layers combining on one web page
Frontend / Fundamentals

How HTML, CSS, and JavaScript Work Together

A hands-on walkthrough for beginners: build one small button, give it structure with HTML, looks with CSS, and behavior with JavaScript, and watch the three layers cooperate on a real page.

Sep 20, 20268 min read
The Frontend Developer Toolkit cover with editor, browser, and CLI motifs
Frontend / Fundamentals

The Frontend Developer Toolkit

A friendly tour of the everyday tools a frontend developer relies on — code editor, browser and DevTools, terminal, version control, package managers, and a dev server — and what each one is actually for.

Sep 20, 202610 min read
Cover illustration for What Frontend Developers Do
Frontend / Fundamentals

What Frontend Developers Do: A Beginner's Guide to the Role

A clear, beginner-friendly look at what frontend developers actually do every day: turning designs into working interfaces, building reusable UI, and caring about responsiveness, accessibility, and speed.

Sep 20, 202610 min read