What is Destructuring?
Destructuring allows you to extract values from arrays or properties from objects into distinct variables using a concise syntax.
📋 Array Destructuring
Basic Array Destructuring
// Traditional way
let colors = ['red', 'green', 'blue'];
let first = colors[0];
let second = colors[1];
let third = colors[2];
// Destructuring
let [first, second, third] = ['red', 'green', 'blue'];
console.log(first); // 'red'
console.log(second); // 'green'
console.log(third); // 'blue'
// Skip elements
let [first, , third] = ['red', 'green', 'blue'];
console.log(first); // 'red'
console.log(third); // 'blue'
// Get first elements
let [x, y] = [1, 2, 3, 4, 5];
console.log(x); // 1
console.log(y); // 2
// More elements than variables
let [a, b] = [1, 2, 3];
console.log(a); // 1
console.log(b); // 2
// Third element is ignored
Default Values
// If value is undefined, use default
let [a = 1, b = 2] = [10];
console.log(a); // 10 (from array)
console.log(b); // 2 (default)
let [x = 5, y = 10] = [undefined, 20];
console.log(x); // 5 (default, because undefined)
console.log(y); // 20 (from array)
// null doesn't trigger default
let [m = 1] = [null];
console.log(m); // null (not default)
// Complex defaults
let [name = 'Guest', age = 18] = ['John'];
console.log(name); // 'John'
console.log(age); // 18
// Default can be expression
let [first = getDefaultValue()] = [];
function getDefaultValue() {
console.log('Called');
return 'default';
}
Rest Pattern
// Collect remaining elements
let [first, ...rest] = [1, 2, 3, 4, 5];
console.log(first); // 1
console.log(rest); // [2, 3, 4, 5]
// Rest must be last
let [a, b, ...others] = [1, 2, 3, 4];
console.log(others); // [3, 4]
// Rest with no remaining elements
let [x, y, ...remaining] = [1, 2];
console.log(remaining); // []
// Practical: split array
let [head, ...tail] = [1, 2, 3, 4];
console.log(head); // 1
console.log(tail); // [2, 3, 4]
Swapping Variables
// Old way (with temp variable)
let a = 1, b = 2;
let temp = a;
a = b;
b = temp;
// Destructuring way
let a = 1, b = 2;
[a, b] = [b, a];
console.log(a); // 2
console.log(b); // 1
// Swap multiple
let x = 1, y = 2, z = 3;
[x, y, z] = [z, x, y];
console.log(x, y, z); // 3, 1, 2
Nested Arrays
// Destructure nested arrays
let nested = [1, [2, 3], 4];
let [a, [b, c], d] = nested;
console.log(a); // 1
console.log(b); // 2
console.log(c); // 3
console.log(d); // 4
// Deep nesting
let deep = [1, [2, [3, 4]]];
let [x, [y, [z, w]]] = deep;
console.log(z); // 3
// Mixed with skip
let [first, [, second]] = [1, [2, 3]];
console.log(first); // 1
console.log(second); // 3
🗃️ Object Destructuring
Basic Object Destructuring
// Traditional way
let user = { name: 'John', age: 30 };
let name = user.name;
let age = user.age;
// Destructuring (variable names match property names)
let { name, age } = { name: 'John', age: 30 };
console.log(name); // 'John'
console.log(age); // 30
// Order doesn't matter
let { age, name } = { name: 'John', age: 30 };
console.log(name); // 'John'
// Select specific properties
let { name } = { name: 'John', age: 30, city: 'NYC' };
console.log(name); // 'John'
// Non-existent property
let { job } = { name: 'John' };
console.log(job); // undefined
Renaming Variables
// Syntax: { propertyName: newVariableName }
let { name: userName, age: userAge } = { name: 'John', age: 30 };
console.log(userName); // 'John'
console.log(userAge); // 30
// console.log(name); // ReferenceError
// Useful for conflicting names
let name = 'Global';
let { name: personName } = { name: 'John' };
console.log(name); // 'Global'
console.log(personName); // 'John'
// Multiple renames
let { firstName: first, lastName: last } = {
firstName: 'John',
lastName: 'Doe'
};
console.log(first); // 'John'
console.log(last); // 'Doe'
Default Values
// If property is undefined, use default
let { name = 'Guest', age = 18 } = { name: 'John' };
console.log(name); // 'John' (from object)
console.log(age); // 18 (default)
// Rename with default
let { name: userName = 'Guest', age: userAge = 18 } = {};
console.log(userName); // 'Guest'
console.log(userAge); // 18
// null doesn't trigger default
let { value = 10 } = { value: null };
console.log(value); // null (not default)
// Complex defaults
let { x = getDefault() } = {};
// Practical: config with defaults
let config = { timeout: 5000 };
let {
timeout = 3000,
retries = 3,
debug = false
} = config;
console.log(timeout); // 5000
console.log(retries); // 3 (default)
console.log(debug); // false (default)
Rest Properties
// Collect remaining properties (ES2018)
let { name, ...rest } = {
name: 'John',
age: 30,
city: 'NYC',
job: 'Developer'
};
console.log(name); // 'John'
console.log(rest); // { age: 30, city: 'NYC', job: 'Developer' }
// Extract some, keep others
let { id, createdAt, ...userData } = {
id: 1,
name: 'John',
age: 30,
createdAt: '2025-01-01'
};
console.log(userData); // { name: 'John', age: 30 }
// Rest must be last
let { a, b, ...others } = { a: 1, b: 2, c: 3, d: 4 };
console.log(others); // { c: 3, d: 4 }
Nested Objects
// Destructure nested objects
let user = {
name: 'John',
address: {
city: 'NYC',
country: 'USA'
}
};
let { name, address: { city, country } } = user;
console.log(name); // 'John'
console.log(city); // 'NYC'
console.log(country); // 'USA'
// console.log(address); // ReferenceError (not extracted)
// Get both parent and children
let {
address,
address: { city }
} = user;
console.log(address); // { city: 'NYC', country: 'USA' }
console.log(city); // 'NYC'
// Deep nesting
let data = {
user: {
profile: {
name: 'John',
age: 30
}
}
};
let { user: { profile: { name, age } } } = data;
console.log(name); // 'John'
console.log(age); // 30
// With defaults
let { address: { zip = '00000' } = {} } = {};
console.log(zip); // '00000'
🔧 Function Parameters
Destructuring Parameters
// Traditional
function printUser(user) {
console.log(user.name);
console.log(user.age);
}
// Destructuring in parameters
function printUser({ name, age }) {
console.log(name);
console.log(age);
}
printUser({ name: 'John', age: 30 });
// Array destructuring in parameters
function sum([a, b]) {
return a + b;
}
console.log(sum([5, 10])); // 15
// With defaults
function greet({ name = 'Guest', greeting = 'Hello' }) {
console.log(`${greeting}, ${name}!`);
}
greet({ name: 'John' }); // "Hello, John!"
greet({ greeting: 'Hi' }); // "Hi, Guest!"
greet({}); // "Hello, Guest!"
// Default for entire parameter
function configure(options = {}) {
let { timeout = 3000, debug = false } = options;
console.log(timeout, debug);
}
configure(); // 3000, false
configure({ timeout: 5000 }); // 5000, false
Named Parameters Pattern
// Without destructuring (hard to remember order)
function createUser(name, age, email, role, active) {
// ...
}
createUser('John', 30, 'john@example.com', 'admin', true);
// With destructuring (self-documenting)
function createUser({ name, age, email, role = 'user', active = true }) {
console.log(`Creating ${role}: ${name}`);
return { name, age, email, role, active };
}
createUser({
name: 'John',
email: 'john@example.com',
age: 30
});
// Partial options
function fetchData({ url, method = 'GET', headers = {}, body }) {
console.log(`${method} ${url}`);
// Make request
}
fetchData({
url: '/api/users',
method: 'POST',
body: { name: 'John' }
});
Return Value Destructuring
// Return multiple values as array
function getCoordinates() {
return [10, 20];
}
let [x, y] = getCoordinates();
console.log(x, y); // 10, 20
// Return multiple values as object
function getUser() {
return {
name: 'John',
age: 30,
email: 'john@example.com'
};
}
let { name, age } = getUser();
console.log(name, age); // 'John', 30
// Practical: API response
async function fetchUser(id) {
let response = await fetch(`/api/users/${id}`);
return response.json();
}
let { data, error } = await fetchUser(1);
// Error handling
function divide(a, b) {
if (b === 0) {
return { success: false, error: 'Division by zero' };
}
return { success: true, result: a / b };
}
let { success, result, error } = divide(10, 2);
if (success) {
console.log('Result:', result);
} else {
console.error('Error:', error);
}
💡 Practical Examples
API Response Handling
// Extract data from API response
async function loadUser(userId) {
let response = await fetch(`/api/users/${userId}`);
let {
data: { name, email, profile: { avatar, bio } },
meta: { timestamp }
} = await response.json();
console.log(`${name} (${email})`);
console.log(`Bio: ${bio}`);
console.log(`Loaded at: ${timestamp}`);
}
// Multiple API calls
async function loadDashboard() {
let [
{ data: users },
{ data: posts },
{ data: stats }
] = await Promise.all([
fetch('/api/users').then(r => r.json()),
fetch('/api/posts').then(r => r.json()),
fetch('/api/stats').then(r => r.json())
]);
return { users, posts, stats };
}
React/Vue Component Props
// React component with destructured props
function UserCard({ name, age, email, avatar = '/default.png', onEdit }) {
return `
${name}
Age: ${age}
Email: ${email}
`;
}
// Vue component
const UserProfile = {
props: ['user'],
setup({ user }) {
let { name, age, email } = user;
return { name, age, email };
}
};
// Nested props
function Dashboard({ user: { name, role }, settings: { theme, language } }) {
console.log(`${name} (${role})`);
console.log(`Theme: ${theme}, Language: ${language}`);
}
Array Manipulation
// Get first and last
let numbers = [1, 2, 3, 4, 5];
let [first, , , , last] = numbers;
console.log(first, last); // 1, 5
// Split array
let [head, ...tail] = [1, 2, 3, 4];
console.log(head); // 1
console.log(tail); // [2, 3, 4]
// Matrix operations
let matrix = [[1, 2], [3, 4], [5, 6]];
let [[a, b], [c, d], [e, f]] = matrix;
// Iterate with destructuring
let users = [
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' }
];
for (let { id, name } of users) {
console.log(`${id}: ${name}`);
}
// Map with destructuring
let formatted = users.map(({ id, name }) => `#${id} ${name}`);
Configuration Objects
// Server configuration
function startServer({
port = 3000,
host = 'localhost',
ssl = false,
database: {
host: dbHost = 'localhost',
port: dbPort = 5432,
name: dbName = 'myapp'
} = {}
} = {}) {
console.log(`Server: ${host}:${port}`);
console.log(`SSL: ${ssl}`);
console.log(`Database: ${dbName} at ${dbHost}:${dbPort}`);
}
startServer({
port: 8080,
database: {
name: 'production'
}
});
// Feature flags
function initializeApp({
features: {
darkMode = false,
analytics = true,
betaFeatures = false
} = {}
} = {}) {
console.log('Features:', { darkMode, analytics, betaFeatures });
}
initializeApp({
features: { darkMode: true }
});
Object Property Filtering
// Remove sensitive data
function sanitizeUser(user) {
let { password, ssn, creditCard, ...safe } = user;
return safe;
}
let user = {
id: 1,
name: 'John',
email: 'john@example.com',
password: 'secret',
ssn: '123-45-6789'
};
let safeUser = sanitizeUser(user);
// { id: 1, name: 'John', email: 'john@example.com' }
// Pick specific fields
function pick(obj, ...keys) {
return keys.reduce((acc, key) => {
if (key in obj) acc[key] = obj[key];
return acc;
}, {});
}
let picked = pick(user, 'id', 'name', 'email');
// Rename keys
function renameKeys(obj, keyMap) {
return Object.entries(obj).reduce((acc, [key, value]) => {
let newKey = keyMap[key] || key;
acc[newKey] = value;
return acc;
}, {});
}
let renamed = renameKeys(
{ firstName: 'John', lastName: 'Doe' },
{ firstName: 'first', lastName: 'last' }
);
// { first: 'John', last: 'Doe' }
Event Handlers
// Extract event properties
button.addEventListener('click', ({ target, clientX, clientY }) => {
console.log('Clicked element:', target);
console.log('Position:', clientX, clientY);
});
// Form handling
form.addEventListener('submit', (event) => {
event.preventDefault();
let formData = new FormData(event.target);
let data = Object.fromEntries(formData);
let { email, password, remember } = data;
console.log('Login:', { email, password, remember });
});
// Keyboard shortcuts
document.addEventListener('keydown', ({ key, ctrlKey, shiftKey, altKey }) => {
if (ctrlKey && key === 's') {
console.log('Save');
} else if (ctrlKey && shiftKey && key === 'P') {
console.log('Command palette');
}
});
🎯 Key Takeaways
- Array Destructuring: Extract values by position: [a, b] = [1, 2]
- Object Destructuring: Extract properties by name: { name, age } = user
- Default Values: Provide fallbacks: { x = 10 } = {}
- Rest Pattern: Collect remaining: [...rest] or {...rest}
- Rename Variables: { name: userName } extracts name as userName
- Nested Destructuring: Access deep properties directly
- Function Parameters: Destructure for named parameters pattern
- Swapping: [a, b] = [b, a] swaps values without temp variable