Suggest an editImprove this articleRefine the answer for “Deep copy of an object”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**A deep copy is a completely independent object together with all of its nested objects and arrays, so changes on the copy never affect the original.** There are four main options: the built-in `structuredClone(obj)` (modern browsers and Node.js 17+, preserves `Date`, `Map`, `Set`, but loses functions and prototypes), the classic `JSON.parse(JSON.stringify(obj))` (works everywhere, but loses functions, `undefined`, `Symbol`, `BigInt`, `Date`, `Map`, `Set`, `RegExp`), `_.cloneDeep(obj)` from lodash (the most reliable for complex structures) and your own recursive function (good for understanding the mechanics, but it does not cover special types). ```javascript const user = { name: 'Alice', address: { city: 'Kyiv' }, tags: ['dev'] }; const clone = structuredClone(user); clone.address.city = 'Lviv'; clone.tags.push('frontend'); console.log(user.address.city); // "Kyiv" console.log(user.tags); // ['dev'] ``` **Key point:** reach for `structuredClone(obj)` by default, and for `_.cloneDeep(obj)` when you need maximum compatibility and stability.Shown above the full answer for quick recall.Answer (EN)Image**To make a deep copy of an object, use the built-in `structuredClone(obj)`, or `_.cloneDeep(obj)` from lodash in larger projects.** A deep copy is a completely independent object, including every nested object and array, so changes on the copy do not affect the original. ## Theory ### TL;DR - A deep copy rebuilds **the whole tree** of the object, not just the top level. - `structuredClone(obj)` is built in, modern and fast, but it does not copy functions or prototypes. - `JSON.parse(JSON.stringify(obj))` works everywhere, but it silently loses many types. - `_.cloneDeep(obj)` from lodash is the most reliable option for complex structures. - Your own recursive function is useful for understanding the mechanics, but it does not cover `Map`, `Set`, `Date`, `RegExp`. - Rule of thumb: `structuredClone()` by default, `cloneDeep()` when you need maximum compatibility. ### Quick example ```javascript const user = { name: 'Alice', address: { city: 'Kyiv', zip: 12345 }, tags: ['dev', 'frontend'] }; const clone = structuredClone(user); clone.address.city = 'Lviv'; clone.tags.push('react'); console.log(user.address.city); // "Kyiv" console.log(user.tags); // ['dev', 'frontend'] ``` ## What a "deep copy" is A **deep copy** is when a **fully independent object** is created, including all **nested objects and arrays**. Changes on the copy **do not affect** the original. The opposite is a shallow copy (`{ ...obj }`, `Object.assign()`), which copies only the top level and leaves nested objects as shared references. ## Option 1: the modern way, `structuredClone()` The most reliable and simplest method, available in every modern browser and in Node.js 17 and newer. ```javascript const user = { name: 'Alice', address: { city: 'Kyiv', zip: 12345 }, tags: ['dev', 'frontend'] }; const clone = structuredClone(user); clone.address.city = 'Lviv'; clone.tags.push('react'); console.log(user.address.city); // "Kyiv" console.log(user.tags); // ['dev', 'frontend'] ``` **Advantages:** - it copies **objects, arrays, dates, `Map`, `Set`** and other structured types; - it is **safe and fast**, because it is implemented in the engine. **Limitations:** - it does not copy **functions** or **prototypes** (they are lost); - it does not support `undefined` as a key (but it does support it as a value). ## Option 2: `JSON.parse(JSON.stringify())` The classic approach that works everywhere, even in old browsers: ```javascript const user = { name: 'Alice', address: { city: 'Kyiv' }, tags: ['frontend', 'dev'] }; const clone = JSON.parse(JSON.stringify(user)); clone.address.city = 'Lviv'; console.log(user.address.city); // "Kyiv" ``` **Advantages:** - simple and universal, with no dependencies. **Drawbacks:** - it loses: - functions; - `undefined`, `Symbol`, `BigInt`; - `Date`, `Map`, `Set`, `RegExp` (they turn into plain objects or strings). - it is slower on very large objects. ## Option 3: lodash (`_.cloneDeep()`) If the project is large or uses TypeScript, this is **the most reliable option**. ```javascript import _ from 'lodash'; const clone = _.cloneDeep(user); ``` **Advantages:** - it deep copies **any data types** (including `Date`, `Map`, `Set`, `Buffer` and so on); - it behaves consistently in every environment. **Drawback:** - it requires installing the library: ```bash npm install lodash ``` ## Option 4: a manual recursive copy (for understanding) If you want to understand the mechanics, here is a basic implementation: ```javascript function deepClone(obj) { if (obj === null || typeof obj !== 'object') return obj; if (Array.isArray(obj)) { return obj.map(deepClone); } const clone = {}; for (const key in obj) { clone[key] = deepClone(obj[key]); } return clone; } const user = { name: 'Alice', address: { city: 'Kyiv' } }; const clone = deepClone(user); clone.address.city = 'Lviv'; console.log(user.address.city); // "Kyiv" ``` It works for plain objects and arrays, but not for `Map`, `Set`, `Date`, `RegExp` and the like: for those you need lodash or `structuredClone`. ## Summary table | Method | Support | Copies nested objects | Preserves types (`Date`, `Map`, `Set`) | Copies functions | | --- | --- | --- | --- | --- | | `structuredClone()` | Modern browsers, Node.js 17+ | Yes | Yes | No | | `JSON.parse(JSON.stringify())` | Everywhere | Yes | No | No | | `_.cloneDeep()` | Through the lodash library | Yes | Yes | No | | Recursive function | Manual implementation | Yes | No | No | **In one sentence:** > For a reliable deep copy use `structuredClone(obj)` when you want a built-in function, and `_.cloneDeep(obj)` when the project is large and stability matters. ### Common mistakes - **Confusing a deep copy with a shallow one.** `{ ...obj }` creates a new object, but the nested structures stay shared. - **Cloning an object with dates through JSON.** After that clone a `Date` is a string, and `clone.createdAt.getTime()` throws. - **Expecting methods to survive the clone.** Neither `structuredClone()`, nor the JSON trick, nor a simple recursion carries the prototype over, so a class instance becomes a plain object. - **Calling `structuredClone()` on an object containing a function.** It throws `DataCloneError` instead of silently dropping the property the way JSON does. - **Using naive recursion on cyclic structures.** Without a cache of already copied objects (a `WeakMap`, for instance) it loops forever and overflows the stack. - **Pulling in lodash for a single call in a modern environment.** `structuredClone()` is already there.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.