How to Use the Spread Operator in JavaScript
Learn how to use the spread operator (...) to expand arrays and objects in JavaScript.
The spread operator (...) expands iterables into individual elements. It’s incredibly useful for copying, merging, and manipulating arrays and objects.
Array Spread
Copying Arrays
const original = [1, 2, 3];
// Create a shallow copy
const copy = [...original];
console.log(copy); // [1, 2, 3]
// Modifying copy doesn't affect original
copy.push(4);
console.log(original); // [1, 2, 3]
console.log(copy); // [1, 2, 3, 4]
Merging Arrays
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const merged = [...arr1, ...arr2];
console.log(merged); // [1, 2, 3, 4, 5, 6]
// Insert elements in between
const inserted = [...arr1, 'middle', ...arr2];
console.log(inserted); // [1, 2, 3, 'middle', 4, 5, 6]
Converting to Array
// String to array
const chars = [..."hello"];
console.log(chars); // ['h', 'e', 'l', 'l', 'o']
// Set to array
const set = new Set([1, 2, 2, 3]);
const unique = [...set];
console.log(unique); // [1, 2, 3]
// NodeList to array
const divs = [...document.querySelectorAll('div')];
Function Arguments
const numbers = [5, 2, 8, 1, 9];
// Pass array elements as arguments
const max = Math.max(...numbers);
console.log(max); // 9
// Instead of apply()
console.log(Math.max.apply(null, numbers)); // Old way
Object Spread
Copying Objects
const original = { a: 1, b: 2 };
// Shallow copy
const copy = { ...original };
console.log(copy); // { a: 1, b: 2 }
// Adding properties
const extended = { ...original, c: 3 };
console.log(extended); // { a: 1, b: 2, c: 3 }
Merging Objects
const defaults = { theme: 'light', lang: 'en' };
const userSettings = { theme: 'dark' };
// Later properties override earlier ones
const settings = { ...defaults, ...userSettings };
console.log(settings); // { theme: 'dark', lang: 'en' }
Updating Properties
const user = { name: 'Alice', age: 30, city: 'NYC' };
// Update specific property
const updated = { ...user, age: 31 };
console.log(updated); // { name: 'Alice', age: 31, city: 'NYC' }
// Original unchanged
console.log(user.age); // 30
Removing Properties
const user = { name: 'Alice', password: 'secret', age: 30 };
// Destructure to remove, spread the rest
const { password, ...safeUser } = user;
console.log(safeUser); // { name: 'Alice', age: 30 }
Rest Parameters
The opposite of spread - collect elements into an array:
// Rest in function parameters
function sum(...numbers) {
return numbers.reduce((a, b) => a + b, 0);
}
console.log(sum(1, 2, 3, 4)); // 10
// Rest in destructuring
const [first, second, ...rest] = [1, 2, 3, 4, 5];
console.log(first); // 1
console.log(rest); // [3, 4, 5]
Practical Examples
Clone and Modify
// Update item in array (immutably)
const todos = [
{ id: 1, text: 'Learn JS', done: false },
{ id: 2, text: 'Build app', done: false }
];
const updated = todos.map(todo =>
todo.id === 1 ? { ...todo, done: true } : todo
);
console.log(updated[0].done); // true
console.log(todos[0].done); // false (unchanged)
Conditional Properties
const includeEmail = true;
const user = {
name: 'Alice',
...(includeEmail && { email: 'alice@example.com' })
};
console.log(user);
// { name: 'Alice', email: 'alice@example.com' }
Default Function Options
function createButton(options = {}) {
const defaults = {
text: 'Click me',
color: 'blue',
size: 'medium'
};
const config = { ...defaults, ...options };
return config;
}
console.log(createButton({ color: 'red' }));
// { text: 'Click me', color: 'red', size: 'medium' }
React State Updates
// Updating state immutably
const [state, setState] = useState({
users: [],
loading: false,
error: null
});
// Update single property
setState(prev => ({ ...prev, loading: true }));
// Add to array
setState(prev => ({
...prev,
users: [...prev.users, newUser]
}));
Array Manipulation
const items = [1, 2, 3, 4, 5];
// Insert at position
const insertAt = (arr, index, item) => [
...arr.slice(0, index),
item,
...arr.slice(index)
];
console.log(insertAt(items, 2, 'new')); // [1, 2, 'new', 3, 4, 5]
// Remove at position
const removeAt = (arr, index) => [
...arr.slice(0, index),
...arr.slice(index + 1)
];
console.log(removeAt(items, 2)); // [1, 2, 4, 5]
Important Notes
Shallow Copy Only
const nested = { a: { b: 1 } };
const copy = { ...nested };
copy.a.b = 2;
console.log(nested.a.b); // 2 (affected!)
// Deep copy needed for nested objects
const deepCopy = JSON.parse(JSON.stringify(nested));
// Or use structuredClone() in modern environments
Order Matters
// Later values override earlier ones
const result = { a: 1, a: 2 };
console.log(result); // { a: 2 }
const merged = { a: 1, ...{ a: 2 } };
console.log(merged); // { a: 2 }
Summary
[...array]- copy/expand arrays{...object}- copy/merge objects...args(rest) - collect into array- Creates shallow copies only
- Later properties override earlier ones
- Essential for immutable updates