Q&A
What is the Object.assign() method in JavaScript?
Overview
Object.assign() (ES6) is the classic way to combine objects: it writes the properties of each source onto the target, left to right, with later sources overwriting earlier ones. It returns the target (now modified). Understanding that it does a shallow copy and mutates the target is the heart of the topic.
graph LR
S1[source1: {a:1}] --> T[target]
S2[source2: {b:2}] --> T
S3[source3: {a:9}] --> T
T --> R["result {a:9, b:2} - later sources win, target mutated"]
style T fill:#1e1b4b,color:#fff
Signature
Object.assign(target, ...sources) // returns target (mutated)
Merging Objects
const a = { x: 1 };
const b = { y: 2 };
const merged = Object.assign({}, a, b); // { x: 1, y: 2 }
Using a fresh {} as the target avoids mutating a or b. Properties from later sources overwrite earlier ones:
Object.assign({}, { v: 1 }, { v: 2 }); // { v: 2 } - last wins
Shallow Cloning
const original = { name: "Ada", info: { age: 30 } };
const copy = Object.assign({}, original);
copy.name = "Linus"; // doesn't affect original (primitive copied)
copy.info.age = 99; // ⚠ DOES affect original.info.age - shared reference!
This is the key gotcha: top-level primitives are copied by value, but nested objects are shared by reference. For a deep clone, use structuredClone(original) or a library.
Applying Defaults
function configure(options) {
const defaults = { color: "blue", size: "md", debug: false };
return Object.assign({}, defaults, options); // options override defaults
}
configure({ size: "lg" }); // { color: "blue", size: "lg", debug: false }
It Mutates and Returns the Target
const target = { a: 1 };
const result = Object.assign(target, { b: 2 });
console.log(target); // { a: 1, b: 2 } - target was modified
console.log(result === target); // true - returns the same object
If you don't want to mutate an existing object, pass {} as the first argument.
The Modern Alternative: Spread Syntax
The object spread operator (...) is now the more common, readable way to do the same shallow merge/clone:
const merged = { ...a, ...b }; // same as Object.assign({}, a, b)
const copy = { ...original }; // shallow clone
const withDefaults = { ...defaults, ...options };
Spread is preferred for readability; Object.assign is still useful when you specifically want to mutate an existing target (spread always creates a new object).
What It Copies (and doesn't)
- Copies enumerable own properties (not inherited/prototype ones).
- Copies Symbol-keyed properties too.
- Triggers getters on the source and setters on the target.
- Does not deep-copy; does not copy non-enumerable properties.
Why This Matters in Interviews
JS interviews use Object.assign to test object manipulation and - above all - the shallow vs deep copy distinction. Be ready to explain: it mutates and returns the target, later sources overwrite earlier, nested objects are shared by reference (so mutating a nested property leaks into the original), and that spread ({...}) is the modern equivalent except it never mutates. Mentioning structuredClone for true deep copies is a strong addition.
Common Pitfalls
- Assuming it deep-clones - nested objects/arrays are shared references.
- Forgetting it mutates the first argument; pass
{}to avoid changing a source. - Expecting it to copy inherited/prototype properties (it only copies own enumerable ones).
- Using it where spread would be clearer (unless mutation of an existing object is intended).