JavaScript Tutorial

Destructuring Arrays & Objects in JavaScript: Complete Guide

Master JavaScript destructuring — unpack arrays and objects into clean variables, use default values, rename keys, nested destructuring, function parameter destructuring, and real-world examples with best practices.

Welcome back! 👋 In the previous lesson, you mastered JavaScript objects in depth. Now let's explore one of the most useful ES6 features that makes working with both arrays and objects dramatically cleaner — Destructuring!

Destructuring lets you unpack values from arrays or properties from objects into individual variables in a single, clean line. You'll see it in every modern JavaScript codebase — in function parameters, API response handling, React components, and more.

Once you understand destructuring, your code will be noticeably shorter and much more readable. Let's dive in!


What is Destructuring?

Destructuring is a syntax that lets you extract values from arrays or objects and assign them to variables — all in one step.

// Without destructuring — verbose
let user = { name: "Mihir", age: 25, city: "Mumbai" };
let name = user.name;
let age  = user.age;
let city = user.city;

// With destructuring — clean and concise ✅
let { name, age, city } = user;

console.log(name); // "Mihir"
console.log(age);  // 25
console.log(city); // "Mumbai"

Same result — half the code. That's destructuring.


Part 1: Array Destructuring

Array destructuring extracts values based on position (index).

Basic Syntax

let [first, second, third] = array;

Basic Example

let fruits = ["Apple", "Banana", "Mango", "Orange"];

let [first, second, third] = fruits;

console.log(first);  // "Apple"
console.log(second); // "Banana"
console.log(third);  // "Mango"

Skip Elements with Commas

Use an empty comma , to skip positions you don't need.

let scores = [92, 85, 78, 60, 55];

let [top, , third] = scores; // Skip index 1

console.log(top);   // 92
console.log(third); // 78
let colors = ["Red", "Green", "Blue", "Yellow", "Purple"];

let [, , , fourth] = colors; // Skip first three

console.log(fourth); // "Yellow"

Default Values

Provide a fallback when the value at that position is undefined.

let [a = 10, b = 20, c = 30] = [1, 2];

console.log(a); // 1  (from array)
console.log(b); // 2  (from array)
console.log(c); // 30 (default — nothing at index 2)
let [username = "Guest", role = "viewer"] = ["Mihir"];

console.log(username); // "Mihir"  (from array)
console.log(role);     // "viewer" (default)

Rest Elements ...

Capture remaining elements into a new array.

let [first, second, ...rest] = [1, 2, 3, 4, 5];

console.log(first);  // 1
console.log(second); // 2
console.log(rest);   // [3, 4, 5]
let [head, ...tail] = ["Apple", "Banana", "Mango", "Orange"];

console.log(head); // "Apple"
console.log(tail); // ["Banana", "Mango", "Orange"]

Swap Variables — Classic Trick

let x = 5;
let y = 10;

// ❌ Old way — needs temp variable
let temp = x;
x = y;
y = temp;

// ✅ Destructuring swap — clean and elegant
[x, y] = [y, x];

console.log(x); // 10
console.log(y); // 5

Destructure Function Return Values

function getMinMax(numbers) {
  return [Math.min(...numbers), Math.max(...numbers)];
}

let [min, max] = getMinMax([3, 1, 9, 5, 7]);

console.log(`Min: ${min}`); // Min: 1
console.log(`Max: ${max}`); // Max: 9

Part 2: Object Destructuring

Object destructuring extracts values based on key name — not position.

Basic Syntax

let { key1, key2, key3 } = object;

Basic Example

let user = {
  name:  "Mihir",
  age:   25,
  city:  "Mumbai",
  role:  "Admin",
};

let { name, age, city } = user;

console.log(name); // "Mihir"
console.log(age);  // 25
console.log(city); // "Mumbai"

Rename While Destructuring

Use : to assign to a different variable name.

let user = { name: "Mihir", age: 25 };

// Rename 'name' → 'username', 'age' → 'userAge'
let { name: username, age: userAge } = user;

console.log(username); // "Mihir"
console.log(userAge);  // 25
// console.log(name);  // ❌ ReferenceError — 'name' doesn't exist here

Default Values

Provide a fallback when the key doesn't exist or is undefined.

let user = { name: "Mihir", age: 25 };

let { name, age, role = "viewer", city = "Unknown" } = user;

console.log(name);  // "Mihir"
console.log(age);   // 25
console.log(role);  // "viewer"  (default — not in object)
console.log(city);  // "Unknown" (default — not in object)

Rename + Default Values Together

let config = { theme: "dark" };

let {
  theme: currentTheme = "light",
  fontSize: size = 14,
  language: lang = "en",
} = config;

console.log(currentTheme); // "dark"   (from object)
console.log(size);         // 14       (default)
console.log(lang);         // "en"     (default)

Rest Properties ...

Capture remaining properties into a new object.

let user = { name: "Mihir", age: 25, city: "Mumbai", role: "Admin" };

let { name, age, ...rest } = user;

console.log(name); // "Mihir"
console.log(age);  // 25
console.log(rest); // { city: "Mumbai", role: "Admin" }

Part 3: Nested Destructuring

Destructure values from deeply nested arrays and objects.

Nested Object Destructuring

let student = {
  name: "Mihir",
  marks: {
    math:    92,
    science: 88,
    english: 85,
  },
  address: {
    city:  "Mumbai",
    state: "Maharashtra",
  },
};

// Destructure nested properties
let {
  name,
  marks: { math, science, english },
  address: { city, state },
} = student;

console.log(name);    // "Mihir"
console.log(math);    // 92
console.log science); // 88
console.log(city);    // "Mumbai"
console.log(state);   // "Maharashtra"

Nested Array Destructuring

let matrix = [[1, 2], [3, 4], [5, 6]];

let [[a, b], [c, d], [e, f]] = matrix;

console.log(a, b); // 1 2
console.log(c, d); // 3 4
console.log(e, f); // 5 6

Mixed — Object with Arrays Inside

let employee = {
  name:   "Priya",
  skills: ["JavaScript", "React", "Node.js"],
  scores: { technical: 92, communication: 88 },
};

let {
  name,
  skills: [primarySkill, ...otherSkills],
  scores: { technical, communication },
} = employee;

console.log(name);          // "Priya"
console.log(primarySkill);  // "JavaScript"
console.log(otherSkills);   // ["React", "Node.js"]
console.log(technical);     // 92
console.log(communication); // 88

Part 4: Destructuring in Function Parameters

This is where destructuring truly shines in real-world code — pass an object to a function and destructure directly in the parameter list.

Object Parameter Destructuring

// ❌ Old way — access properties one by one inside
function displayUser(user) {
  console.log(`${user.name} | ${user.role} | ${user.city}`);
}

// ✅ Destructure in parameter — direct access
function displayUser({ name, role, city }) {
  console.log(`${name} | ${role} | ${city}`);
}

displayUser({ name: "Mihir", role: "Admin", city: "Mumbai" });
// Output: Mihir | Admin | Mumbai

With Default Values in Parameters

function createProfile({ name, role = "viewer", active = true, city = "Unknown" }) {
  return {
    name,
    role,
    active,
    city,
    createdAt: new Date().toLocaleDateString(),
  };
}

let profile1 = createProfile({ name: "Mihir", role: "admin", city: "Mumbai" });
let profile2 = createProfile({ name: "Priya" }); // uses all defaults

console.log(profile1);
// { name: "Mihir", role: "admin", active: true, city: "Mumbai", createdAt: "..." }

console.log(profile2);
// { name: "Priya", role: "viewer", active: true, city: "Unknown", createdAt: "..." }

Array Parameter Destructuring

function getFirstAndLast([first, ...rest]) {
  return { first, last: rest[rest.length - 1] };
}

let result = getFirstAndLast([10, 20, 30, 40, 50]);
console.log(result); // { first: 10, last: 50 }

Destructure Inside forEach / map

let students = [
  { name: "Mihir",  marks: 92, dept: "CS" },
  { name: "Priya",  marks: 85, dept: "IT" },
  { name: "Rahul",  marks: 78, dept: "CS" },
];

// Destructure each student object directly in the callback
students.forEach(({ name, marks, dept }) => {
  console.log(`${name} (${dept}): ${marks} marks`);
});
// Output:
// Mihir (CS): 92 marks
// Priya (IT): 85 marks
// Rahul (CS): 78 marks
// Map with destructuring
let summaries = students.map(({ name, marks }) =>
  `${name}: ${marks >= 75 ? "Pass ✅" : "Fail ❌"}`
);

console.log(summaries);
// ["Mihir: Pass ✅", "Priya: Pass ✅", "Rahul: Pass ✅"]

Part 5: Destructuring with for...of

let users = [
  { name: "Mihir", role: "Admin",  active: true  },
  { name: "Priya", role: "Editor", active: true  },
  { name: "Rahul", role: "Viewer", active: false },
];

for (let { name, role, active } of users) {
  console.log(`${active ? "✅" : "❌"} ${name.padEnd(8)}${role}`);
}
// Output:
// ✅ Mihir    — Admin
// ✅ Priya    — Editor
// ❌ Rahul    — Viewer
// With Object.entries()
let scores = { math: 92, science: 88, english: 85, history: 76 };

for (let [subject, score] of Object.entries(scores)) {
  let grade = score >= 90 ? "A" : score >= 75 ? "B" : "C";
  console.log(`${subject.padEnd(10)}: ${score} (${grade})`);
}
// Output:
// math      : 92 (A)
// science   : 88 (B)
// english   : 85 (B)
// history   : 76 (B)

Real-World Examples

Example 1: Process API Response

// Simulated API response
let apiResponse = {
  status:  200,
  message: "Success",
  data: {
    user: {
      id:    1,
      name:  "Mihir Shah",
      email: "mihir@example.com",
      plan:  "pro",
      stats: {
        posts:     42,
        followers: 1280,
        following: 95,
      },
    },
    token: "eyJhbGciOiJIUzI1NiJ9...",
  },
};

// Extract exactly what you need in one destructure
let {
  status,
  data: {
    user: {
      name,
      email,
      plan,
      stats: { posts, followers },
    },
    token,
  },
} = apiResponse;

console.log(`Status:    ${status}`);
console.log(`User:      ${name} (${email})`);
console.log(`Plan:      ${plan}`);
console.log(`Posts:     ${posts}`);
console.log(`Followers: ${followers}`);
console.log(`Token:     ${token.slice(0, 20)}...`);
// Output:
// Status:    200
// User:      Mihir Shah (mihir@example.com)
// Plan:      pro
// Posts:     42
// Followers: 1280
// Token:     eyJhbGciOiJIUzI1N...

Example 2: Settings Merge with Defaults

const DEFAULTS = {
  theme:         "light",
  language:      "en",
  fontSize:      14,
  notifications: true,
  autoSave:      true,
};

function applySettings(userSettings = {}) {
  const {
    theme         = DEFAULTS.theme,
    language      = DEFAULTS.language,
    fontSize      = DEFAULTS.fontSize,
    notifications = DEFAULTS.notifications,
    autoSave      = DEFAULTS.autoSave,
  } = userSettings;

  console.log("Applied Settings:");
  console.log(`  theme:         ${theme}`);
  console.log(`  language:      ${language}`);
  console.log(`  fontSize:      ${fontSize}`);
  console.log(`  notifications: ${notifications}`);
  console.log(`  autoSave:      ${autoSave}`);

  return { theme, language, fontSize, notifications, autoSave };
}

applySettings({ theme: "dark", fontSize: 16 });
// Applied Settings:
//   theme:         dark
//   language:      en    (default)
//   fontSize:      16
//   notifications: true  (default)
//   autoSave:      true  (default)

Example 3: Restructure Data from API

// Raw API data with snake_case keys
let rawUsers = [
  { user_id: 1, first_name: "Mihir",  last_name: "Shah",  is_active: true,  role_id: 1 },
  { user_id: 2, first_name: "Priya",  last_name: "Nair",  is_active: false, role_id: 2 },
  { user_id: 3, first_name: "Rahul",  last_name: "Gupta", is_active: true,  role_id: 2 },
];

const ROLES = { 1: "Admin", 2: "Editor" };

// Transform using destructuring + rename
let cleanUsers = rawUsers.map(({
  user_id:    id,
  first_name: firstName,
  last_name:  lastName,
  is_active:  isActive,
  role_id:    roleId,
}) => ({
  id,
  name:   `${firstName} ${lastName}`,
  active: isActive,
  role:   ROLES[roleId],
}));

console.log(cleanUsers);
// [
//   { id: 1, name: "Mihir Shah",  active: true,  role: "Admin"  },
//   { id: 2, name: "Priya Nair",  active: false, role: "Editor" },
//   { id: 3, name: "Rahul Gupta", active: true,  role: "Editor" },
// ]

Example 4: Cart Summary with Destructuring

let cart = [
  { name: "Laptop",   price: 55000, qty: 1, discount: 10 },
  { name: "Mouse",    price: 800,   qty: 2, discount: 0  },
  { name: "Keyboard", price: 1500,  qty: 1, discount: 5  },
];

function calcLineTotal({ price, qty, discount }) {
  let discounted = price * (1 - discount / 100);
  return discounted * qty;
}

console.log("=== 🛒 Cart Summary ===");
let grandTotal = 0;

for (let item of cart) {
  let { name, price, qty, discount } = item;
  let lineTotal = calcLineTotal(item);
  grandTotal += lineTotal;

  console.log(
    `${name.padEnd(12)}${price} × ${qty}` +
    `${discount ? ` (-${discount}%)` : ""}` +
    ` = ₹${lineTotal.toLocaleString()}`
  );
}

console.log(`${"─".repeat(40)}`);
console.log(`TOTAL: ₹${grandTotal.toLocaleString()}`);
// Output:
// Laptop       ₹55000 × 1 (-10%) = ₹49,500
// Mouse        ₹800 × 2 = ₹1,600
// Keyboard     ₹1500 × 1 (-5%) = ₹1,425
// ────────────────────────────────────────
// TOTAL: ₹52,525

Destructuring Cheat Sheet

Array Destructuring

// Basic
let [a, b, c] = [1, 2, 3];

// Skip elements
let [a, , c] = [1, 2, 3];

// Default values
let [a = 10, b = 20] = [1];

// Rest elements
let [first, ...rest] = [1, 2, 3, 4, 5];

// Swap variables
[a, b] = [b, a];

// From function return
let [min, max] = getMinMax(array);

Object Destructuring

// Basic
let { name, age } = user;

// Rename
let { name: userName } = user;

// Default values
let { role = "viewer" } = user;

// Rename + default
let { role: userRole = "viewer" } = user;

// Rest properties
let { name, ...rest } = user;

// In function params
function fn({ name, age = 0 }) { ... }

// Nested
let { address: { city } } = user;

Common Mistakes

Mistake 1: Destructuring undefined or null

let user = null;

// ❌ Cannot destructure null — TypeError!
let { name } = user; // TypeError: Cannot destructure property 'name' of null

// ✅ Use default value or guard
let { name } = user ?? {};       // safe — destructures empty object
let { name } = user || {};       // also common pattern

Mistake 2: Forgetting Curly Braces for Object Destructuring in Standalone Statement

let name, age;

// ❌ JS reads { as a block, not destructuring!
{ name, age } = { name: "Mihir", age: 25 }; // SyntaxError

// ✅ Wrap in parentheses when not using let/const/var
({ name, age } = { name: "Mihir", age: 25 }); // ✅

// ✅ Or just use let/const
let { name, age } = { name: "Mihir", age: 25 }; // ✅

Mistake 3: Array Destructuring is Position-Based

let [a, b, c] = [1, 2, 3];

// ❌ You can't skip by name — only by position
let [, , third] = [1, 2, 3]; // must skip with comma

// ✅ If you want named access — use object destructuring instead
let { first, third } = { first: 1, second: 2, third: 3 };

Mistake 4: Nested Destructuring — Missing Intermediate Key

let user = { name: "Mihir" }; // No 'address' key

// ❌ Trying to destructure from a key that doesn't exist
let { address: { city } } = user;
// TypeError: Cannot destructure property 'city' of undefined

// ✅ Provide default for the nested object
let { address: { city } = {} } = user;
console.log(city); // undefined — safe ✅

Mistake 5: Confusing Rest ... in Arrays vs Objects

// ✅ Rest in array — collects remaining elements into array
let [first, ...others] = [1, 2, 3, 4];
console.log(others); // [2, 3, 4]

// ✅ Rest in object — collects remaining properties into object
let { name, ...details } = { name: "Mihir", age: 25, city: "Mumbai" };
console.log(details); // { age: 25, city: "Mumbai" }

// ❌ Rest must ALWAYS be last
let { ...rest, name } = user; // SyntaxError — rest must be last!

Practical Exercise

Create a file called destructuring.js:

// 🎯 Destructuring Practice

// 1. Array destructuring — coordinate system
console.log("=== 📍 Coordinates ===");
let points = [[10, 20], [35, 45], [60, 80]];

for (let [x, y] of points) {
  let distance = Math.sqrt(x ** 2 + y ** 2).toFixed(2);
  console.log(`Point (${x}, ${y}) → Distance from origin: ${distance}`);
}


// 2. Object destructuring — employee processing
console.log("\n=== 👨‍💼 Employee Report ===");
let employees = [
  { name: "Mihir",  dept: "Engineering", salary: 85000, yrs: 3 },
  { name: "Priya",  dept: "Design",      salary: 72000, yrs: 5 },
  { name: "Rahul",  dept: "Engineering", salary: 91000, yrs: 7 },
  { name: "Sara",   dept: "Marketing",   salary: 68000, yrs: 2 },
];

let totalSalary = 0;

for (let { name, dept, salary, yrs } of employees) {
  let bonus   = yrs >= 5 ? salary * 0.15 : salary * 0.08;
  let totalComp = salary + bonus;
  totalSalary += totalComp;

  console.log(
    `${name.padEnd(8)} | ${dept.padEnd(14)} | ` +
    `₹${salary.toLocaleString().padStart(7)} + ` +
    `Bonus ₹${Math.round(bonus).toLocaleString().padStart(6)} = ` +
    `₹${Math.round(totalComp).toLocaleString()}`
  );
}

console.log(`\nTotal Payroll: ₹${Math.round(totalSalary).toLocaleString()}`);


// 3. Nested destructuring — API response
console.log("\n=== 🌐 API Response Parser ===");
let responses = [
  {
    status: 200,
    data: { user: { name: "Mihir", plan: "pro"  }, credits: 500 },
  },
  {
    status: 200,
    data: { user: { name: "Priya", plan: "free" }, credits: 100 },
  },
  {
    status: 403,
    data: { user: { name: "Guest", plan: "none" }, credits: 0   },
  },
];

for (let { status, data: { user: { name, plan }, credits } } of responses) {
  let access = status === 200 ? "✅ Allowed" : "❌ Denied";
  console.log(`${access} | ${name.padEnd(8)} | Plan: ${plan.padEnd(5)} | Credits: ${credits}`);
}


// 4. Function parameter destructuring — build UI cards
console.log("\n=== 🃏 Product Cards ===");
function renderCard({ name, price, rating = 0, inStock = false, discount = 0 }) {
  let finalPrice  = discount ? price * (1 - discount / 100) : price;
  let stockLabel  = inStock ? "🟢 In Stock" : "🔴 Out of Stock";
  let priceLabel  = discount
    ? `₹${finalPrice.toLocaleString()} (${discount}% off)`
    : `₹${price.toLocaleString()}`;

  console.log(`\n📦 ${name}`);
  console.log(`   Price  : ${priceLabel}`);
  console.log(`   Rating : ${"⭐".repeat(Math.round(rating))} (${rating})`);
  console.log(`   Status : ${stockLabel}`);
}

let products = [
  { name: "Wireless Headphones", price: 4999, rating: 4.5, inStock: true,  discount: 20 },
  { name: "Mechanical Keyboard", price: 6500, rating: 4.2, inStock: false              },
  { name: "USB-C Hub",           price: 1299, rating: 3.8, inStock: true               },
];

products.forEach(renderCard);

Run it:

node destructuring.js

Expected Output:

=== 📍 Coordinates ===
Point (10, 20) → Distance from origin: 22.36
Point (35, 45) → Distance from origin: 57.01
Point (60, 80) → Distance from origin: 100.00

=== 👨‍💼 Employee Report ===
Mihir    | Engineering   | ₹ 85,000 + Bonus6,800 = ₹91,800
Priya    | Design        | ₹ 72,000 + Bonus10,800 = ₹82,800
Rahul    | Engineering   | ₹ 91,000 + Bonus13,650 = ₹1,04,650
Sara     | Marketing     | ₹ 68,000 + Bonus5,440 = ₹73,440

Total Payroll: ₹3,52,690

=== 🌐 API Response Parser ===
✅ Allowed | Mihir    | Plan: pro   | Credits: 500Allowed | Priya    | Plan: free  | Credits: 100Denied  | Guest    | Plan: none  | Credits: 0

=== 🃏 Product Cards ===
📦 Wireless Headphones
   Price  : ₹3,999.2 (20% off)
   Rating : ⭐⭐⭐⭐⭐ (4.5)
   Status : 🟢 In Stock

📦 Mechanical Keyboard
   Price  : ₹6,500
   Rating : ⭐⭐⭐⭐ (4.2)
   Status : 🔴 Out of Stock

Key Takeaways

Congratulations! 🎉 You now fully understand destructuring — one of the most powerful and widely used ES6 features.

Array destructuring — extracts by position. Use commas to skip, ... for rest.

Object destructuring — extracts by key name. Order doesn't matter.

Rename with :{ name: userName } pulls name into a variable called userName.

Default values{ role = "viewer" } or [count = 0] — used when value is undefined.

Rest ... — collects remaining items into array or remaining properties into object. Must always be last.

Nested destructuring — go as deep as you need. Provide = {} defaults for potentially missing nested objects.

Function parameter destructuring — the most common real-world use. Makes function signatures self-documenting.

Use with for...of and array methods — destructure directly in loop variables and callbacks.


Best Practices

  1. ✅ Use object destructuring for functions with 3+ parameters — much cleaner than positional args
  2. ✅ Always provide default values for optional destructured properties in function params
  3. ✅ Use rename + default together for API responses: { user_name: name = "Guest" }
  4. ✅ Provide a fallback = {} when destructuring a potentially null or undefined object
  5. ✅ Keep nested destructuring to 2 levels max — deeper gets hard to read
  6. ✅ Use rest ... to cleanly separate known fields from dynamic extras
  7. ✅ Use array destructuring for fixed-position returns like [error, result] patterns
  8. ✅ Destructure inside forEach, map, and for...of callbacks — eliminates repetitive item.property access

What's Next?

Excellent work! 🎉 Destructuring is one of those features that once you start using, you'll never want to go back.

Next up, the final lesson in the Working with Data Structures section:

Working with JSON → — the universal data format for every API and web service you'll ever work with. Learn to parse, stringify, validate, and handle JSON like a pro!

Let's keep going! 💪