Destructuring & Spread
Learn how to extract values from arrays and objects using destructuring, and combine data with the spread operator.
Array Destructuring
Array destructuring allows you to unpack values from arrays into distinct variables using a syntax that mirrors array literals. The values are assigned based on position, and you can skip elements by leaving gaps with commas. Default values can be provided for cases where the array element is undefined. Array destructuring works with any iterable, not just arrays, making it compatible with strings, Sets, Maps, and generators.
// Basic array destructuring
const [first, second, third] = [10, 20, 30];
console.log(first, second, third); // 10 20 30
// Skip elements
const [, , thirdColor] = ["red", "green", "blue"];
console.log(thirdColor); // "blue"
// Default values
const [a = 1, b = 2, c = 3] = [10, 20];
console.log(a, b, c); // 10 20 3
// Rest pattern
const [head, ...tail] = [1, 2, 3, 4, 5];
console.log(head); // 1
console.log(tail); // [2, 3, 4, 5]
// Swap variables without temp
let x = "hello";
let y = "world";
[x, y] = [y, x];
console.log(x, y); // "world" "hello"
// From function returns
function getMinMax(arr) {
return [Math.min(...arr), Math.max(...arr)];
}
const [min, max] = getMinMax([3, 1, 4, 1, 5, 9]);
console.log(`Min: ${min}, Max: ${max}`); // Min: 1, Max: 9
// Nested destructuring
const matrix = [[1, 2], [3, 4]];
const [[a1, a2], [b1, b2]] = matrix;
console.log(a1, a2, b1, b2); // 1 2 3 4
Object Destructuring
Object destructuring extracts properties from objects into variables, matching by property name rather than position. You can rename variables using the colon syntax, provide default values for missing properties, and combine both renaming and defaults. Object destructuring is especially powerful in function parameters, where it allows callers to pass named options in any order. Nested destructuring can extract deeply nested values in a single statement.
// Basic object destructuring
const user = { name: "Alice", age: 30, email: "alice@example.com" };
const { name, age, email } = user;
console.log(name, age); // "Alice" 30
// Renaming variables
const { name: userName, age: userAge } = user;
console.log(userName, userAge); // "Alice" 30
// Default values
const { name: n, role = "viewer", active = true } = user;
console.log(role, active); // "viewer" true
// In function parameters
function createUser({ name, age, role = "user", active = true }) {
return { name, age, role, active, createdAt: new Date() };
}
const newUser = createUser({ name: "Bob", age: 25 });
console.log(newUser);
// Nested destructuring
const response = {
data: {
user: { id: 1, profile: { avatar: "photo.jpg" } },
},
status: 200,
};
const {
data: {
user: {
id,
profile: { avatar },
},
},
status,
} = response;
console.log(id, avatar, status); // 1 "photo.jpg" 200
// Computed property names
const key = "name";
const { [key]: value } = user;
console.log(value); // "Alice"
Rest with Destructuring
The rest pattern in destructuring collects the remaining elements into a new array or object. For arrays, rest gathers the remaining elements after the destructured ones into a new array. For objects, rest collects all remaining enumerable own properties into a new object. This is particularly useful for separating known properties from unknown ones, implementing option extraction, or creating shallow copies with some properties omitted.
// Rest with arrays
const [champion, ...runnersUp] = ["Gold", "Silver", "Bronze", "4th", "5th"];
console.log(champion); // "Gold"
console.log(runnersUp); // ["Silver", "Bronze", "4th", "5th"]
// Rest with objects - extract known props
const config = {
host: "localhost",
port: 3000,
debug: true,
verbose: false,
logLevel: "info",
};
const { host, port, ...otherOptions } = config;
console.log(host); // "localhost"
console.log(otherOptions); // { debug: true, verbose: false, logLevel: "info" }
// Omit properties (create object without certain keys)
const { debug, verbose, ...cleanConfig } = config;
console.log(cleanConfig); // { host: "localhost", port: 3000, logLevel: "info" }
// Common API pattern
function updateUser(id, { password, ...updates }) {
// password is extracted and not included in updates
console.log(`Updating user ${id} with:`, updates);
if (password) {
console.log("Also updating password");
}
}
updateUser(1, { name: "Alice", email: "a@b.com", password: "secret" });
// Updating user 1 with: { name: "Alice", email: "a@b.com" }
// Also updating password
Spread Operator Patterns
The spread operator expands iterables into individual elements in array contexts and own enumerable properties in object contexts. For arrays, spread creates shallow copies, concatenates arrays, and converts iterables to arrays. For objects, spread is used to merge objects, override specific properties, and create modified copies without mutation. Later spread properties override earlier ones, making it a clean pattern for applying defaults or updates to configuration objects.
// Immutable array operations
const todos = [
{ id: 1, text: "Learn JS", done: true },
{ id: 2, text: "Learn React", done: false },
];
// Add item immutably
const withNew = [...todos, { id: 3, text: "Build app", done: false }];
// Remove item immutably
const without = todos.filter((t) => t.id !== 1);
// Update item immutably
const updated = todos.map((t) => (t.id === 2 ? { ...t, done: true } : t));
console.log(updated);
// Immutable object operations
const state = { user: "Alice", theme: "dark", lang: "en" };
// Update specific fields
const newState = { ...state, theme: "light" };
console.log(newState); // { user: "Alice", theme: "light", lang: "en" }
// Conditional spread
const isAdmin = true;
const userConfig = {
name: "Alice",
...(isAdmin && { role: "admin", permissions: ["read", "write"] }),
};
console.log(userConfig);
// Merge multiple sources with priority
function configure(userOptions) {
const defaults = { timeout: 5000, retries: 3, cache: true };
const envOverrides = { timeout: 10000 };
return { ...defaults, ...envOverrides, ...userOptions };
}
console.log(configure({ retries: 5 }));
// { timeout: 10000, retries: 5, cache: true }