# JavaScript Destructuring and Spread Operators Explained
Master array destructuring, object destructuring, rest parameters, and spread operator techniques
Destructuring and spread operators are among the most practical ES6 features. This article covers their various uses and techniques.
Array Destructuring
Basic Usage
// Basic destructuring
const [a, b, c] = [1, 2, 3];
console.log(a, b, c); // 1 2 3
// Skip elements
const [first, , third] = [1, 2, 3];
console.log(first, third); // 1 3
// Rest elements
const [head, ...tail] = [1, 2, 3, 4, 5];
console.log(head); // 1
console.log(tail); // [2, 3, 4, 5]
// Default values
const [x = 10, y = 20] = [1];
console.log(x, y); // 1 20
// Nested destructuring
const [a1, [b1, b2], c1] = [1, [2, 3], 4];
console.log(a1, b1, b2, c1); // 1 2 3 4
Practical Techniques
// Swap variables
let a = 1, b = 2;
[a, b] = [b, a];
console.log(a, b); // 2 1
// Function returning multiple values
function getMinMax(arr) {
return [Math.min(...arr), Math.max(...arr)];
}
const [min, max] = getMinMax([3, 1, 4, 1, 5]);
console.log(min, max); // 1 5
// Destructuring function parameters
function processArray([first, second, ...rest]) {
console.log(first); // 1
console.log(second); // 2
console.log(rest); // [3, 4, 5]
}
processArray([1, 2, 3, 4, 5]);
// With regular expressions
const url = 'https://example.com:8080/path';
const [, protocol, host, port] = url.match(/^(\w+):\/\/([^:]+):(\d+)/);
console.log(protocol, host, port); // 'https' 'example.com' '8080'
Object Destructuring
Basic Usage
// Basic destructuring
const user = { name: 'Alice', age: 25 };
const { name, age } = user;
console.log(name, age); // 'Alice' 25
// Renaming
const { name: userName, age: userAge } = user;
console.log(userName, userAge); // 'Alice' 25
// Default values
const { name: n, city = 'Unknown' } = user;
console.log(n, city); // 'Alice' 'Unknown'
// Rename + default value
const { name: n2, city: c = 'NYC' } = user;
console.log(n2, c); // 'Alice' 'NYC'
// Nested destructuring
const person = {
name: 'Bob',
address: {
city: 'Tokyo',
country: 'Japan'
}
};
const { address: { city, country } } = person;
console.log(city, country); // 'Tokyo' 'Japan'
Rest Properties
// Extract some properties, collect the rest
const user = {
id: 1,
name: 'Alice',
age: 25,
email: 'alice@example.com'
};
const { id, ...rest } = user;
console.log(id); // 1
console.log(rest); // { name: 'Alice', age: 25, email: '...' }
// Practical: Remove object property
function removeField(obj, field) {
const { [field]: _, ...rest } = obj;
return rest;
}
removeField(user, 'email');
// { id: 1, name: 'Alice', age: 25 }
Function Parameter Destructuring
// Destructure parameters
function greet({ name, age }) {
console.log(`Hello ${name}, you are ${age}`);
}
greet({ name: 'Alice', age: 25 });
// With default values
function createUser({
name = 'Anonymous',
age = 0,
role = 'user'
} = {}) {
return { name, age, role };
}
createUser(); // { name: 'Anonymous', age: 0, role: 'user' }
createUser({ name: 'Bob' }); // { name: 'Bob', age: 0, role: 'user' }
// Complex default values
function configure({
host = 'localhost',
port = 3000,
ssl: {
enabled = false,
cert = null
} = {}
} = {}) {
return { host, port, ssl: { enabled, cert } };
}
Spread Operator
Array Spread
// Merge arrays
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const merged = [...arr1, ...arr2];
// [1, 2, 3, 4, 5, 6]
// Copy array (shallow copy)
const original = [1, 2, 3];
const copy = [...original];
// Insert in middle
const inserted = [...arr1.slice(0, 2), 'new', ...arr1.slice(2)];
// [1, 2, 'new', 3]
// Convert iterables
const str = 'hello';
const chars = [...str]; // ['h', 'e', 'l', 'l', 'o']
const set = new Set([1, 2, 3]);
const arrFromSet = [...set]; // [1, 2, 3]
// Function calls
const numbers = [1, 5, 3, 9, 2];
Math.max(...numbers); // 9
Object Spread
// Merge objects
const defaults = { host: 'localhost', port: 3000 };
const options = { port: 8080, ssl: true };
const config = { ...defaults, ...options };
// { host: 'localhost', port: 8080, ssl: true }
// Copy object (shallow copy)
const original = { a: 1, b: 2 };
const copy = { ...original };
// Add/override properties
const user = { name: 'Alice', age: 25 };
const updatedUser = { ...user, age: 26, city: 'NYC' };
// { name: 'Alice', age: 26, city: 'NYC' }
// Conditional spread
const condition = true;
const obj = {
always: true,
...(condition && { sometimes: true })
};
// { always: true, sometimes: true }
// Or use ternary
const obj2 = {
...baseObj,
...(isAdmin ? adminProps : userProps)
};
Rest Parameters
Function Parameters
// Collect all arguments
function sum(...numbers) {
return numbers.reduce((a, b) => a + b, 0);
}
sum(1, 2, 3, 4, 5); // 15
// Combine with fixed parameters
function log(level, ...messages) {
console.log(`[${level}]`, ...messages);
}
log('INFO', 'User logged in', 'at 10:00');
// [INFO] User logged in at 10:00
// Replace arguments object
// Old way
function oldWay() {
const args = Array.prototype.slice.call(arguments);
return args.join(' ');
}
// New way (recommended)
function newWay(...args) {
return args.join(' ');
}
Rest in Destructuring
// Array destructuring
const [first, second, ...others] = [1, 2, 3, 4, 5];
console.log(others); // [3, 4, 5]
// Object destructuring
const { a, b, ...remaining } = { a: 1, b: 2, c: 3, d: 4 };
console.log(remaining); // { c: 3, d: 4 }
Advanced Patterns
Dynamic Property Destructuring
const key = 'name';
const obj = { name: 'Alice', age: 25 };
// Computed property name destructuring
const { [key]: value } = obj;
console.log(value); // 'Alice'
// Utility function
function pick(obj, ...keys) {
return keys.reduce((result, key) => {
if (key in obj) {
result[key] = obj[key];
}
return result;
}, {});
}
pick(obj, 'name'); // { name: 'Alice' }
Deep Merge
// Shallow merge (spread operator)
const merged = { ...obj1, ...obj2 }; // Nested objects are overwritten
// Deep merge function
function deepMerge(target, source) {
const result = { ...target };
for (const key of Object.keys(source)) {
if (
source[key] !== null &&
typeof source[key] === 'object' &&
!Array.isArray(source[key]) &&
target[key] !== null &&
typeof target[key] === 'object'
) {
result[key] = deepMerge(target[key], source[key]);
} else {
result[key] = source[key];
}
}
return result;
}
const obj1 = { a: 1, nested: { x: 1, y: 2 } };
const obj2 = { b: 2, nested: { y: 3, z: 4 } };
deepMerge(obj1, obj2);
// { a: 1, b: 2, nested: { x: 1, y: 3, z: 4 } }
React Applications
// Props passing
function ParentComponent() {
const commonProps = { className: 'common', onClick: handleClick };
return <ChildComponent {...commonProps} id="child1" />;
}
// State updates
const [state, setState] = useState({ name: '', age: 0 });
setState(prev => ({ ...prev, name: 'Alice' }));
// Destructure props
function UserCard({ name, age, ...rest }) {
return (
<div {...rest}>
<h2>{name}</h2>
<p>Age: {age}</p>
</div>
);
}
Best Practices Summary
Destructuring and Spread Best Practices:
┌─────────────────────────────────────────────────────┐
│ │
│ Destructuring Usage │
│ ├── Extract needed properties for cleaner code │
│ ├── Use in function params for readability │
│ ├── Provide sensible default values │
│ └── Avoid deeply nested destructuring │
│ │
│ Spread Usage │
│ ├── Keep immutability when merging objects/arrays│
│ ├── Remember it's a shallow copy │
│ ├── Use && or ternary for conditional spread │
│ └── Later properties override earlier ones │
│ │
│ Performance Considerations │
│ ├── Large object spreads have performance cost │
│ ├── Consider alternatives for frequent spreads │
│ └── Deep nesting requires deep merge │
│ │
└─────────────────────────────────────────────────────┘
| Operation | Syntax | Purpose |
|---|---|---|
| Array destructuring | [a, b] = arr | Extract array elements |
| Object destructuring | {a, b} = obj | Extract object properties |
| Array spread | [...arr] | Merge/copy arrays |
| Object spread | {...obj} | Merge/copy objects |
| Rest parameters | ...rest | Collect remaining elements |
Master destructuring and spread for more concise and elegant code.