Destructuring
Destructuring is one of ES6's most elegant features. It allows you to extract values from arrays and objects into distinct variables using concise syntax. This lesson covers array destructuring, object destructuring, and advanced patterns that will make your code cleaner and more expressive.
Array Destructuring Basics
Array destructuring unpacks array values into separate variables:
Old Way (Index Access):
const colors = ["red", "green", "blue"];
const first = colors[0];
const second = colors[1];
const third = colors[2];
New Way (Destructuring):
const colors = ["red", "green", "blue"];
const [first, second, third] = colors;
console.log(first); // "red"
console.log(second); // "green"
console.log(third); // "blue"
You can skip elements you don't need:
const numbers = [1, 2, 3, 4, 5];
// Skip elements with empty slots
const [first, , third, , fifth] = numbers;
console.log(first); // 1
console.log(third); // 3
console.log(fifth); // 5
// Get only what you need
const [a, b] = numbers; // Takes first two elements
console.log(a, b); // 1, 2
Tip: Array destructuring works with any iterable, including strings, Sets, and Maps!
Object Destructuring Basics
Object destructuring extracts properties by name:
Old Way (Dot Notation):
const user = {
name: "John",
age: 25,
city: "New York"
};
const name = user.name;
const age = user.age;
const city = user.city;
New Way (Destructuring):
const user = {
name: "John",
age: 25,
city: "New York"
};
const { name, age, city } = user;
console.log(name); // "John"
console.log(age); // 25
console.log(city); // "New York"
Variable names must match property names (unless you rename them):
const product = {
id: 123,
title: "Laptop",
price: 999
};
// Extract specific properties
const { title, price } = product;
console.log(title); // "Laptop"
console.log(price); // 999
// Rename during destructuring
const { title: productName, price: productPrice } = product;
console.log(productName); // "Laptop"
console.log(productPrice); // 999
Key Difference: Array destructuring uses position (order matters), while object destructuring uses property names (order doesn't matter).
Default Values in Destructuring
Provide fallback values for missing properties or elements:
Array with Defaults:
const colors = ["red"];
const [first = "black", second = "white", third = "gray"] = colors;
console.log(first); // "red" (from array)
console.log(second); // "white" (default)
console.log(third); // "gray" (default)
Object with Defaults:
const user = {
name: "John",
age: 25
};
const { name, age, city = "Unknown", country = "USA" } = user;
console.log(name); // "John"
console.log(age); // 25
console.log(city); // "Unknown" (default)
console.log(country); // "USA" (default)
Defaults work with renaming:
const settings = {
theme: "dark"
};
const {
theme = "light",
fontSize: size = 14,
language: lang = "en"
} = settings;
console.log(theme); // "dark" (from object)
console.log(size); // 14 (default, renamed from fontSize)
console.log(lang); // "en" (default, renamed from language)
Rest Pattern in Destructuring
The rest operator (...) collects remaining elements:
Rest in Arrays:
const numbers = [1, 2, 3, 4, 5];
const [first, second, ...rest] = numbers;
console.log(first); // 1
console.log(second); // 2
console.log(rest); // [3, 4, 5]
Rest in Objects:
const user = {
name: "John",
age: 25,
city: "New York",
country: "USA",
email: "john@example.com"
};
const { name, age, ...otherInfo } = user;
console.log(name); // "John"
console.log(age); // 25
console.log(otherInfo); // { city: "New York", country: "USA", email: "john@example.com" }
Important: The rest element must be the last element in destructuring. const [first, ...rest, last] = arr; is invalid!
Nested Destructuring
Destructure nested objects and arrays:
Nested Objects:
const user = {
name: "John",
age: 25,
address: {
street: "123 Main St",
city: "New York",
country: "USA"
}
};
// Destructure nested address
const {
name,
address: { city, country }
} = user;
console.log(name); // "John"
console.log(city); // "New York"
console.log(country); // "USA"
console.log(address); // ReferenceError: address is not defined
Nested Arrays:
const data = [1, [2, 3], [4, [5, 6]]];
const [a, [b, c], [d, [e, f]]] = data;
console.log(a); // 1
console.log(b); // 2
console.log(c); // 3
console.log(d); // 4
console.log(e); // 5
console.log(f); // 6
Mixed Nested Destructuring:
const response = {
status: 200,
data: {
users: [
{ id: 1, name: "John" },
{ id: 2, name: "Jane" }
]
}
};
const {
status,
data: {
users: [firstUser, secondUser]
}
} = response;
console.log(status); // 200
console.log(firstUser); // { id: 1, name: "John" }
console.log(secondUser); // { id: 2, name: "Jane" }
Destructuring in Function Parameters
One of the most powerful uses of destructuring:
Object Parameters (named parameters):
// Old way
function createUser(name, age, city, country) {
// Easy to mix up parameter order!
console.log(name, age, city, country);
}
createUser("John", 25, "New York", "USA");
// New way with destructuring
function createUser({ name, age, city, country }) {
console.log(name, age, city, country);
}
// Order doesn't matter!
createUser({
country: "USA",
name: "John",
city: "New York",
age: 25
});
With default values:
function greet({ name = "Guest", greeting = "Hello" } = {}) {
console.log(`${greeting}, ${name}!`);
}
greet({ name: "John" }); // "Hello, John!"
greet({ greeting: "Hi" }); // "Hi, Guest!"
greet({}); // "Hello, Guest!"
greet(); // "Hello, Guest!" (empty object default)
Array parameter destructuring:
function sumFirstTwo([a, b]) {
return a + b;
}
console.log(sumFirstTwo([5, 3, 10, 20])); // 8 (5 + 3)
function processCoordinates([x, y, z = 0]) {
console.log(`X: ${x}, Y: ${y}, Z: ${z}`);
}
processCoordinates([10, 20]); // "X: 10, Y: 20, Z: 0"
processCoordinates([10, 20, 30]); // "X: 10, Y: 20, Z: 30"
Practical Applications and Patterns
Swapping Variables:
let a = 1;
let b = 2;
[a, b] = [b, a]; // Swap without temp variable
console.log(a); // 2
console.log(b); // 1
Returning Multiple Values:
function getMinMax(numbers) {
return {
min: Math.min(...numbers),
max: Math.max(...numbers)
};
}
const { min, max } = getMinMax([5, 2, 8, 1, 9]);
console.log(min, max); // 1, 9
Working with Fetch API:
fetch("https://api.example.com/user/123")
.then(response => response.json())
.then(({ name, email, avatar }) => {
console.log(`Name: ${name}`);
console.log(`Email: ${email}`);
console.log(`Avatar: ${avatar}`);
});
Extracting Values from Arrays:
const [year, month, day] = "2024-12-25".split("-");
console.log(year, month, day); // "2024", "12", "25"
const url = "https://example.com/products/123";
const [, , , category, id] = url.split("/");
console.log(category, id); // "products", "123"
React Props Destructuring (common pattern):
// Instead of:
function UserCard(props) {
return `<h2>${props.name}</h2><p>${props.age}</p>`;
}
// Use destructuring:
function UserCard({ name, age, city = "Unknown" }) {
return `<h2>${name}</h2><p>Age: ${age}, City: ${city}</p>`;
}
Configuration Options:
function initializeApp({
theme = "light",
language = "en",
notifications = true,
analytics = false
} = {}) {
console.log("Theme:", theme);
console.log("Language:", language);
console.log("Notifications:", notifications);
console.log("Analytics:", analytics);
}
// Use with partial options
initializeApp({ theme: "dark", analytics: true });
Practice Exercise:
Refactor this code using destructuring:
const user = {
firstName: "John",
lastName: "Doe",
age: 25,
address: {
street: "123 Main St",
city: "New York"
},
hobbies: ["reading", "coding", "gaming"]
};
const firstName = user.firstName;
const lastName = user.lastName;
const city = user.address.city;
const firstHobby = user.hobbies[0];
const secondHobby = user.hobbies[1];
function displayUser(user) {
console.log("Name: " + user.firstName + " " + user.lastName);
console.log("Age: " + user.age);
console.log("City: " + user.address.city);
}
Solution:
const user = {
firstName: "John",
lastName: "Doe",
age: 25,
address: {
street: "123 Main St",
city: "New York"
},
hobbies: ["reading", "coding", "gaming"]
};
// Destructure top-level and nested properties
const {
firstName,
lastName,
address: { city },
hobbies: [firstHobby, secondHobby]
} = user;
// Function parameter destructuring
function displayUser({ firstName, lastName, age, address: { city } }) {
console.log(`Name: ${firstName} ${lastName}`);
console.log(`Age: ${age}`);
console.log(`City: ${city}`);
}
displayUser(user);
Common Patterns in Real Applications
Working with API Responses:
async function fetchUserData(userId) {
const response = await fetch(`/api/users/${userId}`);
const {
data: { user, posts },
status,
message
} = await response.json();
return { user, posts, status, message };
}
State Management (Redux pattern):
const state = {
user: { name: "John", loggedIn: true },
settings: { theme: "dark", notifications: true },
cart: { items: [], total: 0 }
};
const {
user: { name, loggedIn },
settings: { theme },
cart: { total }
} = state;
Handling Multiple Return Values:
function divideWithRemainder(dividend, divisor) {
return {
quotient: Math.floor(dividend / divisor),
remainder: dividend % divisor
};
}
const { quotient, remainder } = divideWithRemainder(17, 5);
console.log(`${quotient} remainder ${remainder}`); // "3 remainder 2"
Summary
In this lesson, you learned:
- Array destructuring extracts values by position:
[a, b, c] = arr
- Object destructuring extracts values by name:
{ name, age } = obj
- Default values provide fallbacks:
{ name = "Guest" } = obj
- Rest operator collects remaining elements:
{ name, ...rest } = obj
- Nested destructuring accesses deep properties
- Function parameter destructuring creates named parameters
- Destructuring makes code more readable and expressive
- Common patterns: swapping variables, multiple returns, API responses
Next Up: In the next lesson, we'll explore the spread and rest operators in depth - powerful tools for working with arrays and objects!