Object.assign()
Copies own enumerable properties from source objects onto a target object and returns it.
Object.assign(target, source1, source2, /* …, */ sourceN)- Added in JavaScript ES2015
Parameters
| Parameter | Type | Description |
|---|---|---|
$target | Object | The target object to apply the sources' properties to. It is mutated and then returned. Primitives are converted to objects. |
$source1, …, sourceNoptional | Object | One or more source objects containing the properties to copy. null and undefined sources are ignored. |
Return value
ObjectThe modified target object — the same reference that was passed in, not a new object.
Errors
Throws a TypeError if target is null or undefined, or if a property assignment fails — for example when the target property is non-writable or a setter on the target throws.
Object.assign() copies own enumerable properties — string keys and symbol keys — from each source onto the target, left to right, so later sources overwrite earlier ones. It mutates and returns the target rather than producing a new object; passing {} as the target is what makes it a copy.
When to reach for it
The two everyday uses are merging options over defaults, Object.assign({}, defaults, userOptions), and mutating an existing object in place, Object.assign(state, patch). Object spread ({ ...a, ...b }) covers the first case more readably; Object.assign() is still the right tool when the target must be an existing object you cannot replace.
What trips people up
The copy is shallow. Nested objects are copied by reference, so mutating copy.nested.x also changes original.nested.x. Use structuredClone() for a deep copy.
Getters on a source are invoked and their results copied as plain data properties — the accessor itself is not preserved. Setters on the target are invoked. And if an assignment throws partway through, the properties copied before the error stay on the target; there is no rollback.
Example
When to use it
- Merge user-supplied options over a defaults object without mutating the defaults
- Apply a patch to an existing state object that other code already holds a reference to
- Collect several partial objects into one payload before sending it
- Copy properties onto an instance inside a constructor
Frequently asked questions
Does Object.assign() deep copy nested objects?
No — it is a shallow copy, so nested objects are shared by reference between the source and the result; use structuredClone() when you need a deep copy.
What is the difference between Object.assign() and object spread?
Spread ({ ...a, ...b }) always creates a new object and defines properties directly, while Object.assign() mutates an existing target and triggers setters on it — so use spread for copies and Object.assign() when the target must stay the same reference.
Why is Object.assign() not copying some properties?
It only copies own enumerable properties; inherited properties and anything defined with enumerable: false are skipped.
More examples
Getters are flattened to values
The descriptor shows a plain writable data property with value 42 — the getter ran once during the copy and was not carried over.
const source = {
get computed() {
return 6 * 7;
},
};
const copy = Object.assign({}, source);
console.log(copy.computed);
console.log(Object.getOwnPropertyDescriptor(copy, "computed"));Inherited and non-enumerable properties are skipped
Only { visible: 3 } is copied: the prototype property and the non-enumerable property are both excluded.
const obj = Object.create(
{ fromProto: 1 },
{
hidden: { value: 2, enumerable: false },
visible: { value: 3, enumerable: true },
},
);
console.log(Object.assign({}, obj));A failed assignment stops the copy
Prints 2 and undefined — the copy stopped at the non-writable property, keeping what it had already written and never reaching b.
const target = Object.defineProperty({}, "locked", { value: 1, writable: false });
try {
Object.assign(target, { a: 2 }, { locked: 3, b: 4 });
} catch (err) {
console.log(err.constructor.name);
}
console.log(target.a, target.b);
Discussion