Suggest an editImprove this articleRefine the answer for “Copying with Object.assign”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**`Object.assign()` makes a shallow copy: only the first level of properties is copied, so nested objects and arrays land in the copy by reference, not by value.** Primitives (`string`, `number`, `boolean`) are copied by value and live independently afterwards, but any change inside a nested object is visible in both the original and the copy, because it is physically the same object in memory. ```javascript const user = { name: 'Alice', address: { city: 'Kyiv' } }; const clone = Object.assign({}, user); clone.address.city = 'Lviv'; console.log(user.address.city); // 'Lviv', the original changed too ``` **Key point:** `Object.assign()` copies only the top level; for an independent copy of nested structures you need `structuredClone()` or another deep clone.Shown above the full answer for quick recall.Answer (EN)Image**`Object.assign()` creates a shallow copy: it transfers only the source's own enumerable first-level properties into the target.** That means nested objects and arrays are copied by reference, so the original and the copy keep sharing the very same inner structures. ## Theory ### TL;DR - `Object.assign()` gives you a **shallow copy**, not a deep one. - Only the **first level** of properties is copied. - Primitives (`string`, `number`, `boolean`) are copied **by value** and become independent. - Nested objects, arrays and functions are copied **by reference**. - Changing a field inside a nested object is visible in both the original and the copy. - For an independent copy use `structuredClone()`, `JSON.parse(JSON.stringify())` or `cloneDeep()` from Lodash. ### Quick example ```javascript const user = { name: 'Alice', address: { city: 'Kyiv', zip: 12345 } }; const clone = Object.assign({}, user); clone.address.city = 'Lviv'; console.log(user.address.city); // 'Lviv', not 'Kyiv' ``` Why this happens: - `Object.assign()` copies only the **first level of properties**; - the `address` property is an **object**, so the **reference** to it is copied; - a change inside the nested object (`city`) shows up in the original. ### What this looks like in memory ```javascript user.address ────┐ │ (one and the same object) clone.address ────┘ ``` Both objects, `user` and `clone`, point to **one and the same** `address`. So a change inside `address` affects both. What `user` and `clone` hold is not the address structure itself but the memory address of that structure, and `Object.assign()` honestly copied exactly that. ### But primitive properties are copied properly ```javascript const user = { name: 'Alice', age: 25 }; const clone = Object.assign({}, user); clone.name = 'Oleh'; console.log(user.name); // 'Alice', independent ``` A primitive has no inner structure that could be shared, so the value itself lands in the copy. Only **nested objects or arrays** stay shared (and functions too, since a function is an object as well). ### How to avoid the problem If you need a **deep copy**, use one of these. `structuredClone()`, the built-in modern way: ```javascript const clone = structuredClone(user); clone.address.city = 'Lviv'; console.log(user.address.city); // 'Kyiv', the original is untouched ``` `JSON.parse(JSON.stringify())`, universal but limited (it loses `undefined` and functions, turns `Date` into a string, and throws on circular references): ```javascript const clone = JSON.parse(JSON.stringify(user)); ``` `_.cloneDeep()` from Lodash, reliable and compatible with every type: ```javascript import _ from 'lodash'; const clone = _.cloneDeep(user); ``` ### Summary: what Object.assign actually copies | What `Object.assign()` copies | Behaviour | | --- | --- | | Primitive values (`string`, `number`, `boolean`) | copied by value | | Nested objects and arrays | copied **by reference** | | Functions | copied by reference | | Deep structures | not copied independently | ### Common mistakes - **Treating `Object.assign({}, obj)` as a full clone.** It is only the top level; anything nested stays shared. - **Assuming spread does something different.** `{ ...obj }` has exactly the same shallow semantics as `Object.assign({}, obj)`. - **Mutating a nested object in application state after "copying" it.** In React or Redux this is a classic source of bugs: the reference did not change, so the component does not re-render, yet the original is already corrupted. - **Applying `JSON.parse(JSON.stringify())` blindly.** The trick silently drops `undefined` and functions, turns `Date` into a string, and throws on circular references. - **Forgetting that `Object.assign()` mutates the target.** The first argument is changed in place, so `Object.assign(user, patch)` is not copying, it is updating `user`.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.