The Spread Operator (...), introduced for objects in ES2018, allows you to copy properties from one object into another. It provides a concise, declarative syntax for shallow cloning, merging datasets, and updating state without mutating the original object.
1. Basic Syntax and Usage
The operator “unpacks” the key-value pairs of an object. It is most commonly used within an object literal to create a new object.
const user = { name: 'Alice', age: 25 };
// Cloning the object
const userCopy = { ...user };
console.log(userCopy); // { name: 'Alice', age: 25 }
2. Merging Objects
You can spread multiple objects into a single new object. If the objects share the same keys, the last one spread will overwrite the previous values.
const defaults = { theme: 'light', fontSize: 14 };
const userSettings = { theme: 'dark' };
const finalConfig = { ...defaults, ...userSettings };
console.log(finalConfig); // { theme: 'dark', fontSize: 14 }
3. The “Shallow Copy” Constraint
It is vital to remember that the spread operator performs a shallow copy. It copies the top-level primitives by value, but for nested objects or arrays, it only copies the reference.
The Side Effect Risk:
const original = { id: 1, info: { status: 'active' } };
const clone = { ...original };
// Modifying a nested property in the clone...
clone.info.status = 'offline';
// ...also affects the original!
console.log(original.info.status); // 'offline'
4. Advanced Use Cases
A. Merging Multiple Objects
You can spread an unlimited number of objects into one. This is common in state management patterns (like Redux or React’s useState).
const part1 = { a: 1 };
const part2 = { b: 2 };
const part3 = { c: 3 };
const combined = { ...part1, ...part2, ...part3 };
B. Immutably Updating Nested State
Since state in modern frameworks should be treated as immutable, the spread operator is used to “create a new version” of an object without modifying the old one.
const state = { id: 1, meta: { status: "pending" } };
// Correct way to update nested properties immutably
const newState = {
...state,
meta: {
...state.meta,
status: "completed"
}
};
C. Conditionally Adding Properties
You can use the spread operator in combination with short-circuit evaluation (&&) to conditionally include properties in an object.
const isPremium = true;
const user = {
name: "Sarah",
...(isPremium && { badge: "👑" })
};
5. Rest Properties
The spread operator’s “twin” is the Rest Pattern, used during destructuring. It allows you to extract specific properties from an object and collect all remaining properties into a new variable.
const settings = {
theme: "dark",
volume: 80,
notifications: true,
autoUpdate: false
};
// Destructure theme and volume, put the "rest" in others
const { theme, volume, ...others } = settings;
console.log(theme); // "dark"
console.log(others); // { notifications: true, autoUpdate: false }
6. Performance and Edge Cases
Null and Undefined
One of the safety features of the object spread operator is that it ignores null and undefined without throwing an error. This makes it safer for merging optional configurations.
const config = null;
const finalConfig = { default: true, ...config };
// Result: { default: true } (No error thrown!)
Prototypal Properties
The spread operator only copies own enumerable properties. Properties inherited through the prototype chain are ignored.
const proto = { inherited: "yes" };
const obj = Object.create(proto);
obj.own = "no";
const spreaded = { ...obj };
console.log(spreaded.inherited); // undefined
console.log(spreaded.own); // "no"
