Spread Expands an Object Into Another
The object spread syntax — three dots in front of an object — copies that object's own enumerable properties into the surrounding object literal. It's the shortest path to cloning, merging, and producing modified copies without touching the original.
copy has the same keys and values as user, but it's a different object. Mutating one won't affect the other — at least at the top level. We'll come back to that caveat shortly.
The mental model: { ...obj } says "pour the properties of obj into this new object literal." Anything you write alongside the spread becomes part of the result.
Cloning and Overriding in One Step
The most common pattern is spreading an object and then adding or overriding a few properties. Later keys win, so you spread first and override after:
user is untouched. updated is a new object with role replaced. This immutable-update pattern shows up everywhere in modern JavaScript — React state updaters, Redux reducers, any code that prefers not to mutate in place.
Flip the order and you get the opposite behavior:
Here role: "guest" comes first, so user.role overrides it. Handy when you want defaults that the spread object can override.
Merging Objects
Spread two (or more) objects into a new literal to merge them. Later objects override earlier ones on conflicting keys:
theme and fontSize come from userPrefs; debug falls through from defaults. Three objects? Four? Same rule — read left to right, last write wins.
This is the modern replacement for Object.assign({}, defaults, userPrefs). Both do the same thing, but the spread version is easier to read and doesn't tempt you into the common bug of writing Object.assign(defaults, userPrefs) — which mutates defaults.
Spread Is a Shallow Copy
This is the part that catches people. Spread copies the top-level properties of an object. If a property's value is itself an object or an array, the reference is copied, not the contents.
Changing copy.address.city also changed user.address.city — because both objects share the same address object. The spread only gave us a new outer wrapper.
When you need to modify something nested, spread each level you want to change:
For a genuinely deep clone of arbitrary data, reach for structuredClone(obj). It handles nested objects, arrays, dates, maps, and sets — and it's built into every modern runtime.
Spread vs. Rest
They share the same three dots but do opposite things. Spread expands; rest collects.
The rule of thumb: if the ... is on the left side of an = (destructuring), it's rest. If it's inside an object or array literal on the right side, it's spread.
Removing a Property Immutably
Combining rest destructuring with spread gives you a clean way to produce a copy of an object with one key removed — no delete, no mutation:
tempToken is pulled out into its own variable (which you ignore), and everything else lands in safe. The original user is untouched.
What Spread Doesn't Copy
A few subtleties worth knowing:
- Non-enumerable properties aren't copied. Most properties you create are enumerable by default, but properties defined with
Object.definePropertyand certain built-ins aren't. - The prototype isn't copied.
{ ...instance }gives you a plain object, not an instance of the original class. Methods defined on the class prototype won't be on the copy. - Getters are evaluated. Spreading an object with a getter calls the getter once and stores the returned value as a normal property on the new object.
copy has x and y, but it's a plain object — distance lives on Point.prototype, which spread didn't touch. If you need to clone a class instance, the class usually has to provide its own clone method.
Next: Array Methods
Spread is one piece of the immutable-data toolkit. The other big piece is array methods — map, filter, reduce, and friends — which produce new arrays instead of mutating the originals. That's the next page.
Frequently Asked Questions
What does ...obj do in JavaScript?
Inside an object literal, ...obj copies all of that object's own enumerable properties into the new object. { ...user } produces a fresh object with the same keys and values as user. It's the standard way to clone or merge objects without mutating the originals.
How do I merge two objects in JavaScript?
Spread both into a new object literal: const merged = { ...a, ...b }. Properties from b override matching keys from a because later properties win. This is equivalent to Object.assign({}, a, b) but reads more cleanly.
Is object spread a deep copy?
No. Object spread is a shallow copy — it copies top-level properties, but nested objects and arrays are still shared by reference. Mutating copy.address.city will also mutate original.address.city. For a true deep copy, use structuredClone(obj).
What's the difference between spread and rest?
They look identical (...) but do opposite jobs. Spread expands an object or array into individual properties or elements: { ...user }. Rest collects leftovers into one variable: const { name, ...others } = user. Context tells you which one you're looking at.