JavaScript Object Destructuring Complete Guide
Master JavaScript object destructuring from basic syntax to advanced patterns. Covers extracting properties, renaming variables, default values, nested destructuring, rest syntax, and function parameter patterns with real-world examples.
Object destructuring is an ES6 feature that lets you extract properties from objects and assign them to variables in a single statement. Instead of accessing each property one by one with dot notation, destructuring pulls out exactly what you need in a clean, readable syntax. It is one of the most-used ES6 features in modern JavaScript and appears everywhere: variable declarations, function parameters, loop iterations, and import statements.
This guide covers every destructuring pattern from basic extraction to nested objects, default values, renaming, and advanced real-world usage.
Basic Object Destructuring
Wrap the property names you want to extract in curly braces on the left side of the assignment:
const user = {
name: "Alice",
age: 28,
email: "alice@example.com",
role: "developer"
};
// Extract specific properties
const { name, age, email } = user;
console.log(name); // "Alice"
console.log(age); // 28
console.log(email); // "alice@example.com"The variable names must match the property names. Order does not matter:
const { email, name } = user; // Same result, different order
console.log(name); // "Alice"
console.log(email); // "alice@example.com"Renaming Variables During Destructuring
Use a colon after the property name to assign it to a differently named variable:
const apiResponse = {
user_name: "alice_j",
user_email: "alice@example.com",
account_type: "premium"
};
// Rename snake_case to camelCase
const {
user_name: userName,
user_email: userEmail,
account_type: accountType
} = apiResponse;
console.log(userName); // "alice_j"
console.log(userEmail); // "alice@example.com"
console.log(accountType); // "premium"
// Note: user_name, user_email, account_type are NOT defined as variablesRenaming to Avoid Conflicts
const userA = { name: "Alice", score: 92 };
const userB = { name: "Bob", score: 85 };
const { name: nameA, score: scoreA } = userA;
const { name: nameB, score: scoreB } = userB;
console.log(nameA, scoreA); // "Alice" 92
console.log(nameB, scoreB); // "Bob" 85Default Values
Provide fallback values for properties that might not exist on the object:
const config = {
theme: "dark",
language: "en"
};
const {
theme,
language,
fontSize = 16, // Default: not in config
showSidebar = true, // Default: not in config
notifications = false // Default: not in config
} = config;
console.log(theme); // "dark" (from object)
console.log(fontSize); // 16 (default applied)
console.log(showSidebar); // true (default applied)
console.log(notifications); // false (default applied)Defaults with Renaming Combined
const response = {
status_code: 200,
data: { items: [] }
};
const {
status_code: statusCode = 500,
error_message: errorMessage = "No error",
data: responseData = null
} = response;
console.log(statusCode); // 200 (from object, renamed)
console.log(errorMessage); // "No error" (default, renamed)
console.log(responseData); // { items: [] } (from object, renamed)When Defaults Apply
Defaults only apply when the property value is undefined, not null or other falsy values:
const data = {
a: undefined,
b: null,
c: 0,
d: "",
e: false
};
const {
a = "default", // "default" — undefined triggers default
b = "default", // null — default NOT applied
c = "default", // 0 — default NOT applied
d = "default", // "" — default NOT applied
e = "default" // false — default NOT applied
} = data;
console.log(a); // "default"
console.log(b); // null
console.log(c); // 0
console.log(d); // ""
console.log(e); // falseNested Object Destructuring
Extract properties from objects inside objects:
const order = {
id: "ORD-001",
customer: {
name: "Alice",
email: "alice@example.com",
address: {
street: "123 Main St",
city: "San Francisco",
state: "CA",
zip: "94102"
}
},
total: 159.99
};
const {
id,
customer: {
name: customerName,
address: { city, state, zip }
},
total
} = order;
console.log(id); // "ORD-001"
console.log(customerName); // "Alice"
console.log(city); // "San Francisco"
console.log(state); // "CA"
console.log(total); // 159.99Important: When destructuring nested properties, the intermediate variable (like customer and address above) is NOT created as a variable. Only the leaf values become variables.
Safe Nested Destructuring with Defaults
const user = {
name: "Alice"
// No address property
};
// Without default: would throw TypeError
// const { address: { city } } = user; // ERROR!
// With default: safe
const { address: { city = "Unknown" } = {} } = user;
console.log(city); // "Unknown"Rest Pattern (...rest)
The rest pattern collects remaining properties into a new object:
const user = {
name: "Alice",
age: 28,
email: "alice@example.com",
role: "admin",
department: "engineering"
};
const { name, email, ...rest } = user;
console.log(name); // "Alice"
console.log(email); // "alice@example.com"
console.log(rest); // { age: 28, role: "admin", department: "engineering" }Removing Sensitive Fields
const userRecord = {
id: 42,
name: "Alice",
email: "alice@example.com",
password: "hashed_secret",
ssn: "123-45-6789",
apiKey: "sk_live_abc123"
};
// Remove sensitive fields, keep the rest
const { password, ssn, apiKey, ...safeUser } = userRecord;
console.log(safeUser);
// { id: 42, name: "Alice", email: "alice@example.com" }
// Original unchanged
console.log(userRecord.password); // "hashed_secret"Destructuring in Function Parameters
One of the most powerful uses of destructuring is in function parameters. Instead of receiving an object and accessing properties inside the function body, you destructure directly in the parameter list:
// Without destructuring
function displayUser(user) {
console.log(`${user.name} (${user.age}) - ${user.email}`);
}
// With destructuring
function displayUser({ name, age, email }) {
console.log(`${name} (${age}) - ${email}`);
}
displayUser({ name: "Alice", age: 28, email: "alice@example.com" });
// "Alice (28) - alice@example.com"Function Parameters with Defaults
function createButton({
text = "Click me",
color = "blue",
size = "medium",
disabled = false
} = {}) {
return `<button class="${color} ${size}" ${disabled ? "disabled" : ""}>${text}</button>`;
}
// All defaults
console.log(createButton());
// '<button class="blue medium" >Click me</button>'
// Partial override
console.log(createButton({ text: "Submit", color: "green" }));
// '<button class="green medium" >Submit</button>'The = {} at the end allows calling the function with no arguments at all.
Destructuring in Array Methods
const users = [
{ name: "Alice", age: 28, active: true },
{ name: "Bob", age: 35, active: false },
{ name: "Charlie", age: 22, active: true }
];
// Destructure in map
const names = users.map(({ name }) => name);
console.log(names); // ["Alice", "Bob", "Charlie"]
// Destructure in filter
const activeUsers = users.filter(({ active }) => active);
console.log(activeUsers.length); // 2
// Destructure in forEach
users.forEach(({ name, age }) => {
console.log(`${name} is ${age} years old`);
});
// Destructure in reduce
const totalAge = users.reduce((sum, { age }) => sum + age, 0);
console.log(totalAge); // 85Destructuring in Loops
for...of Loop
const products = [
{ name: "Laptop", price: 999, category: "electronics" },
{ name: "Shirt", price: 29, category: "clothing" },
{ name: "Book", price: 15, category: "education" }
];
for (const { name, price } of products) {
console.log(`${name}: $${price}`);
}
// Laptop: $999
// Shirt: $29
// Book: $15With Object.entries()
const scores = {
Alice: 92,
Bob: 85,
Charlie: 97
};
for (const [name, score] of Object.entries(scores)) {
console.log(`${name} scored ${score}`);
}
// Alice scored 92
// Bob scored 85
// Charlie scored 97Destructuring with Computed Property Names
Use bracket notation inside destructuring to extract dynamically named properties:
const data = {
firstName: "Alice",
lastName: "Johnson",
email: "alice@example.com"
};
const field = "email";
const { [field]: extractedEmail } = data;
console.log(extractedEmail); // "alice@example.com"Swapping Variables
While primarily an array destructuring technique, it highlights destructuring's flexibility:
let a = "hello";
let b = "world";
// Swap without temp variable
[a, b] = [b, a];
console.log(a); // "world"
console.log(b); // "hello"Common Patterns Comparison
| Pattern | Syntax | Use Case |
|---|---|---|
| Basic extract | const { a, b } = obj | Pull specific properties |
| Rename | const { a: x } = obj | Avoid naming conflicts, camelCase |
| Default | const { a = 5 } = obj | Fallback for missing properties |
| Nested | const { a: { b } } = obj | Deep property extraction |
| Rest | const { a, ...rest } = obj | Separate known from unknown props |
| Param | function f({ a, b }) {} | Clean function signatures |
| Computed | const { [key]: val } = obj | Dynamic property extraction |
Best Practices
- Destructure early: Extract needed properties at the top of a function, not inline
- Use defaults for optional properties to avoid
undefinedchecks later - Rename API fields at the destructuring boundary (convert
snake_casetocamelCaseonce) - Limit nesting depth to 2 levels; deeper nesting hurts readability
- Use rest for "everything else" patterns like removing sensitive fields
- Add
= {}to function params when the entire object argument is optional
Common Mistakes to Avoid
Destructuring without a Declaration Keyword
// WRONG: interpreted as a block, not destructuring
// { name, age } = user; // SyntaxError
// CORRECT: wrap in parentheses for existing variables
let name, age;
({ name, age } = { name: "Alice", age: 28 });
console.log(name); // "Alice"Forgetting Default for Nested Destructuring
const data = {};
// WRONG: throws TypeError because data.user is undefined
// const { user: { name } } = data;
// CORRECT: provide default empty object
const { user: { name = "Guest" } = {} } = data;
console.log(name); // "Guest"Rune AI
Key Insights
- Basic syntax:
const { a, b } = objextracts properties into matching variable names - Renaming:
const { old: newName } = objmaps property names to different variable names - Defaults:
const { a = fallback } = objprovides values when properties areundefined - Nested:
const { a: { b } } = objextracts from nested objects in one statement - Rest pattern:
const { known, ...rest } = objseparates specific properties from everything else
Frequently Asked Questions
Does destructuring create a copy of the object?
Can I destructure and keep the whole object too?
Is there a performance cost to destructuring?
Can I use destructuring with `Map` or `Set` objects?
How does destructuring interact with TypeScript?
Conclusion
Object destructuring transforms verbose, repetitive property access into clean, declarative variable extraction. Basic destructuring handles simple extractions, renaming tackles naming conflicts and API conversions, defaults prevent undefined surprises, nested destructuring reaches deep into object hierarchies, and rest syntax splits objects into known and unknown parts. Combined with function parameter destructuring, these patterns make JavaScript code significantly more readable and maintainable.
More in this topic
OffscreenCanvas API in JS for UI Performance
Master the OffscreenCanvas API to offload rendering from the main thread. Covers worker-based 2D and WebGL rendering, animation loops inside workers, bitmap transfer, double buffering, chart rendering pipelines, image processing, and performance measurement strategies.
Advanced Web Workers for High Performance JS
Master Web Workers for truly parallel JavaScript execution. Covers dedicated and shared workers, structured cloning, transferable objects, SharedArrayBuffer with Atomics, worker pools, task scheduling, Comlink RPC patterns, module workers, and performance profiling strategies.
JavaScript Macros and Abstract Code Generation
Master JavaScript code generation techniques for compile-time and runtime metaprogramming. Covers AST manipulation, Babel plugin authorship, tagged template literals as macros, code generation pipelines, source-to-source transformation, compile-time evaluation, and safe eval alternatives.