Destructuring is an ES6 syntax that allows extracting values from arrays or properties from objects into separate variables. For arrays, the syntax [a, b] = array
is used, for objects — {prop1, prop2} = object
. Destructuring simplifies code, makes it more readable and allows easy work with complex data structures.
Key capabilities:
Destructuring is a way of “unpacking” values from arrays or objects into separate variables. It’s syntactic sugar that makes code more concise and readable.
// Before ES6 — traditional way
const user = ['John', 'Smith', 25];
const firstName = user[0];
const lastName = user[1];
const age = user[2];
// ES6 — destructuring
const [firstName, lastName, age] = ['John', 'Smith', 25];
console.log(firstName); // 'John'
console.log(lastName); // 'Smith'
console.log(age); // 25
const colors = ['red', 'green', 'blue'];
const [first, second, third] = colors;
console.log(first); // 'red'
console.log(second); // 'green'
console.log(third); // 'blue'
// You can extract not all elements
const [primary] = colors;
console.log(primary); // 'red'
const [, , tertiary] = colors; // Skip first two
console.log(tertiary); // 'blue'
const numbers = [1, 2];
const [a, b, c = 0] = numbers;
console.log(a); // 1
console.log(b); // 2
console.log(c); // 0 — default value
// Default values work only for undefined
const [x, y = 10] = [5, null];
console.log(x); // 5
console.log(y); // null (not 10!)
const [m, n = 10] = [5, undefined];
console.log(m); // 5
console.log(n); // 10
let a = 1;
let b = 2;
// Traditional way of swapping
let temp = a;
a = b;
b = temp;
// With destructuring
[a, b] = [b, a];
console.log(a); // 2
console.log(b); // 1
// Circular shift
let x = 1, y = 2, z = 3;
[x, y, z] = [z, x, y];
console.log(x, y, z); // 3 1 2
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 must be last
const [head, ...tail] = numbers;
console.log(head); // 1
console.log(tail); // [2, 3, 4, 5]
const nested = [[1, 2], [3, 4], [5, 6]];
const [[a, b], [c, d]] = nested;
console.log(a); // 1
console.log(b); // 2
console.log(c); // 3
console.log(d); // 4
// Mixed destructuring
const matrix = [[1, 2, 3], [4, 5, 6]];
const [row1, [, middle]] = matrix;
console.log(row1); // [1, 2, 3]
console.log(middle); // 5
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'
// Order doesn't matter
const {city: userCity, name: userName} = user;
console.log(userCity); // 'New York'
console.log(userName); // 'John'
const user = {
name: 'Mary',
age: 30,
email: 'maria@example.com'
};
// Renaming during destructuring
const {name: fullName, age: years, email: contact} = user;
console.log(fullName); // 'Mary'
console.log(years); // 30
console.log(contact); // 'maria@example.com'
// Mixed usage
const {name, age: userAge} = user;
console.log(name); // 'Mary'
console.log(userAge); // 30
const user = {
name: 'Peter',
age: 28
};
const {name, age, city = 'Not specified', country = 'USA'} = user;
console.log(name); // 'Peter'
console.log(age); // 28
console.log(city); // 'Not specified'
console.log(country); // 'USA'
// Combining with renaming
const {name: userName, profession = 'Not specified'} = user;
console.log(userName); // 'Peter'
console.log(profession); // 'Not specified'
const user = {
name: 'Anna',
address: {
street: 'Broadway',
house: 10,
city: 'New York'
},
contacts: {
phone: '+1-123-456-78-90',
email: 'anna@example.com'
}
};
// Destructuring nested objects
const {
name,
address: {street, city},
contacts: {email}
} = user;
console.log(name); // 'Anna'
console.log(street); // 'Broadway'
console.log(city); // 'New York'
console.log(email); // 'anna@example.com'
// With renaming and default values
const {
address: {street: userStreet, country = 'USA'}
} = user;
console.log(userStreet); // 'Broadway'
console.log(country); // 'USA'
const user = {
id: 1,
name: 'David',
age: 35,
email: 'david@example.com',
phone: '+1-987-654-32-10'
};
const {id, name, ...otherInfo} = user;
console.log(id); // 1
console.log(name); // 'David'
console.log(otherInfo); // {age: 35, email: '...', phone: '...'}
// Excluding specific properties
const {id: userId, ...userWithoutId} = user;
console.log(userId); // 1
console.log(userWithoutId); // {name: 'David', age: 35, ...}
// Destructuring in function parameters
function greetUser({name, age, city = 'Unknown'}) {
return `Hello, ${name}! You are ${age} years old, living in ${city}.`;
}
const user = {name: 'Elena', age: 27, city: 'San Francisco'};
console.log(greetUser(user));
// 'Hello, Elena! You are 27 years old, living in San Francisco.'
// Array destructuring in parameters
function calculateDistance([x1, y1], [x2, y2]) {
return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
}
const point1 = [0, 0];
const point2 = [3, 4];
console.log(calculateDistance(point1, point2)); // 5
// Typical API response
const apiResponse = {
status: 'success',
data: {
users: [
{id: 1, name: 'John', role: 'admin'},
{id: 2, name: 'Mary', role: 'user'}
],
total: 2,
page: 1
},
meta: {
timestamp: '2024-01-15T10:30:00Z',
version: '1.0'
}
};
// Extracting needed data
const {
status,
data: {users, total},
meta: {timestamp}
} = apiResponse;
console.log(status); // 'success'
console.log(users); // array of users
console.log(total); // 2
console.log(timestamp); // '2024-01-15T10:30:00Z'
// Destructuring first user
const [{name: firstUserName, role: firstUserRole}] = users;
console.log(firstUserName); // 'John'
console.log(firstUserRole); // 'admin'
// Importing specific functions
import {useState, useEffect, useCallback} from 'react';
// Destructuring exports
const {log, error, warn} = console;
log('Message'); // Same as console.log('Message')
// Destructuring function result
function getCoordinates() {
return {x: 10, y: 20, z: 30};
}
const {x, y} = getCoordinates();
console.log(x, y); // 10 20
// Extracting first and last elements
const numbers = [1, 2, 3, 4, 5];
const [first, ...middle] = numbers;
const last = middle.pop();
console.log(first); // 1
console.log(last); // 5
// More elegant way
const [firstNum, , , , lastNum] = numbers;
console.log(firstNum, lastNum); // 1 5
// Grouping elements
const items = ['a', 'b', 'c', 'd', 'e', 'f'];
const [group1, group2, ...rest] = items;
console.log(group1); // 'a'
console.log(group2); // 'b'
console.log(rest); // ['c', 'd', 'e', 'f']
function processUser(user) {
// Check object existence
if (!user) return null;
const {name, email, profile = {}} = user;
const {avatar, bio = 'Biography not specified'} = profile;
return {
displayName: name,
contactEmail: email,
userAvatar: avatar,
userBio: bio
};
}
// Safe destructuring with ?? operator
const user = null;
const {name = 'Guest'} = user ?? {};
console.log(name); // 'Guest'
const users = [
{name: 'John', age: 25, city: 'New York'},
{name: 'Mary', age: 30, city: 'San Francisco'},
{name: 'Peter', age: 35, city: 'Chicago'}
];
// Destructuring in for...of
for (const {name, city} of users) {
console.log(`${name} lives in ${city}`);
}
// Destructuring in array methods
const names = users.map(({name}) => name);
console.log(names); // ['John', 'Mary', 'Peter']
const adults = users.filter(({age}) => age >= 30);
console.log(adults); // users over 30
const user = {
firstName: 'Anna',
lastName: 'Johnson',
age: 28,
email: 'anna@example.com'
};
// Dynamic property name
const prop = 'firstName';
const {[prop]: value} = user;
console.log(value); // 'Anna'
// Function to extract specific properties
function pick(obj, ...keys) {
const result = {};
for (const key of keys) {
if (key in obj) {
result[key] = obj[key];
}
}
return result;
}
const userInfo = pick(user, 'firstName', 'email');
console.log(userInfo); // {firstName: 'Anna', email: 'anna@example.com'}
Type | Syntax | Example | Features |
---|---|---|---|
Arrays | [a, b] = array | [x, y] = [1, 2] | By position, order matters |
Objects | {a, b} = object | {name, age} = user | By property name |
Default values | [a = 1] = array | {name = 'Guest'} = user | Only for undefined |
Renaming | {a: newName} | {name: userName} = user | Only for objects |
Rest | [a, ...rest] | {id, ...other} = user | Collects remaining elements |
Nested | [a, [b, c]] | {user: {name}} = data | Multi-level structure |
// ❌ Too complex destructuring
const {
data: {
users: [
{
profile: {
contacts: {email: userEmail}
}
}
]
}
} = complexApiResponse;
// ✅ Step-by-step destructuring
const {data} = complexApiResponse;
const {users} = data;
const [firstUser] = users;
const {profile} = firstUser;
const {contacts} = profile;
const {email: userEmail} = contacts;
// ❌ Unsafe destructuring
function getFullName(user) {
const {firstName, lastName} = user; // Error if user = null
return `${firstName} ${lastName}`;
}
// ✅ Safe destructuring
function getFullName(user = {}) {
const {firstName = '', lastName = ''} = user;
return `${firstName} ${lastName}`.trim() || 'Name not specified';
}
// ✅ With validation
function getFullName(user) {
if (!user || typeof user !== 'object') {
return 'Invalid data';
}
const {firstName = '', lastName = ''} = user;
return `${firstName} ${lastName}`.trim() || 'Name not specified';
}
// ❌ Excessive destructuring in loops
for (let i = 0; i < users.length; i++) {
const {name, email, profile: {avatar}} = users[i]; // Every iteration
// processing...
}
// ✅ Optimized version
for (let i = 0; i < users.length; i++) {
const user = users[i];
const name = user.name;
const email = user.email;
const avatar = user.profile?.avatar; // Optional chaining
// processing...
}
// ✅ Or use destructuring in array methods
const processedUsers = users.map(({name, email, profile}) => ({
displayName: name,
contactEmail: email,
hasAvatar: Boolean(profile?.avatar)
}));
const user = {
name: 'John',
address: null
};
// ❌ Error when destructuring null
// const {street} = user.address; // TypeError
// ✅ Safe destructuring
const {street} = user.address ?? {};
console.log(street); // undefined
// ✅ With optional chaining
const street = user.address?.street;
console.log(street); // undefined
class User {
#id;
constructor(id, name) {
this.#id = id;
this.name = name;
}
getPublicData() {
// Return only public data
const {name} = this;
return {name};
}
}
const user = new User(1, 'Mary');
const {name} = user.getPublicData();
console.log(name); // 'Mary'
interface User {
id: number;
name: string;
email?: string;
}
function processUser({id, name, email = 'not specified'}: User) {
return `User ${name} (ID: ${id}, Email: ${email})`;
}
// Typed destructuring
const users: User[] = [
{id: 1, name: 'John'},
{id: 2, name: 'Mary', email: 'mary@example.com'}
];
const [{name: firstName}, {email: secondEmail}] = users;
Condition: Write a function that takes an array of three numbers and returns an array where the first and last elements are swapped.
function swapFirstLast(arr) {
// Your code here
}
console.log(swapFirstLast([1, 2, 3])); // [3, 2, 1]
console.log(swapFirstLast([10, 20, 30])); // [30, 20, 10]
function swapFirstLast(arr) {
const [first, middle, last] = arr;
return [last, middle, first];
}
// Or more universal solution
function swapFirstLast(arr) {
const [first, ...middle] = arr;
const last = middle.pop();
return [last, ...middle, first];
}
Condition: Create a function that extracts name, age, and city from a user object, setting default values.
function getUserInfo(user) {
// Your code here
// Should return object {name, age, city}
// Default values: name = 'Guest', age = 0, city = 'Not specified'
}
const user1 = {name: 'John', age: 25};
const user2 = {city: 'New York'};
const user3 = {};
console.log(getUserInfo(user1)); // {name: 'John', age: 25, city: 'Not specified'}
console.log(getUserInfo(user2)); // {name: 'Guest', age: 0, city: 'New York'}
console.log(getUserInfo(user3)); // {name: 'Guest', age: 0, city: 'Not specified'}
function getUserInfo(user = {}) {
const {
name = 'Guest',
age = 0,
city = 'Not specified'
} = user;
return {name, age, city};
}
Condition: Write a function that extracts email from a nested user structure and safely handles missing data.
function getEmail(userData) {
// Your code here
// Should return email or 'Email not found'
}
const user1 = {
profile: {
contacts: {
email: 'john@example.com'
}
}
};
const user2 = {
profile: {
contacts: {}
}
};
const user3 = {};
console.log(getEmail(user1)); // 'john@example.com'
console.log(getEmail(user2)); // 'Email not found'
console.log(getEmail(user3)); // 'Email not found'
function getEmail(userData = {}) {
const {
profile: {
contacts: {
email = 'Email not found'
} = {}
} = {}
} = userData;
return email;
}
// Alternative solution with optional chaining
function getEmail(userData) {
return userData?.profile?.contacts?.email ?? 'Email not found';
}
Destructuring is a powerful tool of modern JavaScript that:
Mastering destructuring is critically important for modern JavaScript development, especially when working with React, APIs, and complex data structures. Use this syntax wisely, keeping in mind code readability and performance.
Want more articles for interview preparation? Subscribe to EasyAdvice, bookmark the site and improve every day 💪