|
| 1 | +# Shallow Copy vs Deep Copy in JavaScript |
| 2 | + |
| 3 | +Understanding how JavaScript handles data updating is crucial when working with objects and arrays. This guide explains the differences between Shallow Copy and Deep Copy. |
| 4 | + |
| 5 | +## Primitive vs Reference Types |
| 6 | + |
| 7 | +Before diving into copying, it's important to remember: |
| 8 | +* **Primitive types** (string, number, boolean, etc.) are passed by **value**. |
| 9 | +* **Reference types** (objects, arrays) are passed by **reference**. |
| 10 | + |
| 11 | +## Shallow Copy |
| 12 | + |
| 13 | +A **shallow copy** creates a new object, but it does not create copies of nested objects. Instead, it copies the *references* to those nested objects. |
| 14 | + |
| 15 | +NOTE : A shallow copy duplicates the outer container while preserving references to all nested objects, causing shared mutable state across copies. |
| 16 | + |
| 17 | +### Definition |
| 18 | +* Top-level properties are copied by value (if primitive). |
| 19 | +* Nested objects/arrays are copied by reference. |
| 20 | +* **Consequence**: Modifying a nested object in the copy **changes the original**. |
| 21 | + |
| 22 | +### How to create a Shallow Copy |
| 23 | +1. `Object.assign()` |
| 24 | +2. Spread Operator `[...]` or `{...}` |
| 25 | + |
| 26 | +### Example |
| 27 | + |
| 28 | +```javascript |
| 29 | +let original = { |
| 30 | + name: "Aditya", |
| 31 | + social: { |
| 32 | + twitter: "@aditya" |
| 33 | + } |
| 34 | +}; |
| 35 | + |
| 36 | +let shallowCopy = { ...original }; |
| 37 | + |
| 38 | +shallowCopy.name = "Ashok"; // Does NOT affect original (Top-level primitive) |
| 39 | +shallowCopy.social.twitter = "@newHandle"; // AFFECTS original (Nested reference) |
| 40 | + |
| 41 | +console.log(original.name); // "Aditya" |
| 42 | +console.log(original.social.twitter); // "@newHandle" - CHANGED! |
| 43 | +``` |
| 44 | + |
| 45 | +### Visual Representation |
| 46 | + |
| 47 | +```mermaid |
| 48 | +graph LR |
| 49 | + subgraph Memory |
| 50 | + Obj1[Object: {name: "Aditya"}] |
| 51 | + Obj2[Object: {name: "Ashok"}] |
| 52 | + Nested[Shared Nested Object: {twitter: "@newHandle"}] |
| 53 | + end |
| 54 | +
|
| 55 | + Original[Original Var] --> Obj1 |
| 56 | + Copy[Shallow Copy Var] --> Obj2 |
| 57 | +
|
| 58 | + Obj1 -- reference --> Nested |
| 59 | + Obj2 -- reference --> Nested |
| 60 | +
|
| 61 | + style Nested fill:#f9f,stroke:#333 |
| 62 | +``` |
| 63 | + |
| 64 | +> [!WARNING] |
| 65 | +> Use shallow copies only when your object structure is flat (no nested objects) or when you specifically want shared state for nested items. |
| 66 | +
|
| 67 | +--- |
| 68 | + |
| 69 | +## Deep Copy |
| 70 | + |
| 71 | +A **deep copy** creates a completely independent clone of the original object, including all nested objects. |
| 72 | +NOTE : Deep copy recreates the entire object graph with no shared references, requiring recursive traversal and new allocations for every nested structure. |
| 73 | + |
| 74 | +### Definition |
| 75 | +* recursively copies all properties. |
| 76 | +* New memory references are created for every nested object. |
| 77 | +* **Consequence**: Modifying the copy **never affects the original**. |
| 78 | + |
| 79 | +### How to create a Deep Copy |
| 80 | +1. `JSON.parse(JSON.stringify(obj))` (Simple, but has limitations: no functions, symbols, or undefined). |
| 81 | +2. `structuredClone(obj)` (Modern standard). |
| 82 | +3. Lodash `_.cloneDeep(obj)` (External library). |
| 83 | +4. Recursive custom function. |
| 84 | + |
| 85 | +### Example |
| 86 | + |
| 87 | +```javascript |
| 88 | +let original = { |
| 89 | + name: "Aditya", |
| 90 | + social: { |
| 91 | + twitter: "@aditya" |
| 92 | + } |
| 93 | +}; |
| 94 | + |
| 95 | +let deepCopy = JSON.parse(JSON.stringify(original)); |
| 96 | + |
| 97 | +deepCopy.social.twitter = "@deepNew"; |
| 98 | + |
| 99 | +console.log(original.social.twitter); // "@aditya" - Unchanged! |
| 100 | +console.log(deepCopy.social.twitter); // "@deepNew" |
| 101 | +``` |
| 102 | + |
| 103 | +### Visual Representation |
| 104 | + |
| 105 | +```mermaid |
| 106 | +graph LR |
| 107 | + subgraph Memory |
| 108 | + Obj1[Original Object] |
| 109 | + Nested1[Nested Object 1] |
| 110 | + |
| 111 | + Obj2[Deep Copied Object] |
| 112 | + Nested2[Nested Object 2] |
| 113 | + end |
| 114 | +
|
| 115 | + Original[Original Var] --> Obj1 |
| 116 | + Obj1 -- reference --> Nested1 |
| 117 | +
|
| 118 | + Copy[Deep Copy Var] --> Obj2 |
| 119 | + Obj2 -- reference --> Nested2 |
| 120 | +
|
| 121 | + style Obj1 fill:#bef,stroke:#333 |
| 122 | + style Obj2 fill:#bef,stroke:#333 |
| 123 | + style Nested1 fill:#bfb,stroke:#333 |
| 124 | + style Nested2 fill:#bfb,stroke:#333 |
| 125 | +``` |
| 126 | + |
| 127 | +### Comparison Summary |
| 128 | + |
| 129 | +| Feature | Shallow Copy | Deep Copy | |
| 130 | +| :--- | :--- | :--- | |
| 131 | +| **Top-level properties** | Copied | Copied | |
| 132 | +| **Nested Objects** | Shared Reference | Independent Copy | |
| 133 | +| **Memory Usage** | Low | High | |
| 134 | +| **Speed** | Fast | Slow | |
| 135 | +| **Methods** | `Object.assign`, spread | `JSON.parse/stringify`, `structuredClone` | |
| 136 | + |
0 commit comments