Deep vs Shallow Copy in JavaScript
This article explains the fundamental differences between shallow and deep copying of complex objects in JavaScript. You will learn how JavaScript manages object references in memory, the behavior of shallow copies versus deep copies when dealing with nested data structures, the most common methods to create both types of copies, and how to choose the right approach for your applications.
Understanding Object References in JavaScript
JavaScript assigns primitive data types (like numbers, strings, and booleans) by value. When you copy a primitive, a completely separate copy of the data is created.
Complex types (like objects, arrays, and functions) are stored and assigned by reference. Assigning an object to a new variable does not duplicate the object; it simply creates a new reference pointing to the same memory location:
const original = { name: "Alice" };
const copy = original;
copy.name = "Bob";
console.log(original.name); // "Bob" (Both variables point to the same object)To prevent unintended mutations, you must explicitly copy the object using either a shallow or deep copy.
What is a Shallow Copy?
A shallow copy creates a new object and copies the top-level properties of the original object.
- Primitive values at the top level are duplicated by value.
- Nested objects or arrays are copied by reference.
If the original object contains nested structures, the shallow copy and the original object will still share the memory references for those nested properties. Modifying a nested property in the copy will mutate the original object.
Common Methods for Shallow Copying
Spread Operator (
...):const original = { a: 1, nested: { b: 2 } }; const shallowCopy = { ...original }; shallowCopy.a = 99; shallowCopy.nested.b = 42; console.log(original.a); // 1 (Top-level is unaffected) console.log(original.nested.b); // 42 (Nested object is mutated)Object.assign():const shallowCopy = Object.assign({}, original);Array Methods (
slice(),Array.from(),concat()):const originalArr = [1, [2, 3]]; const shallowArr = originalArr.slice(); shallowArr[1][0] = 99; console.log(originalArr[1][0]); // 99
What is a Deep Copy?
A deep copy duplicates the original object and recursively duplicates every nested object, array, or complex data structure contained within it.
The resulting copy is completely independent of the original. Modifying any level of the deep copy—including deeply nested properties—will never alter the original object.
Common Methods for Deep Copying
structuredClone()(Modern Standard): The built-in global methodstructuredClone()is the native standard for deep cloning in modern JavaScript environments (browsers and Node.js 17+). It handles circular references, Maps, Sets, Dates, and TypedArrays.const original = { a: 1, nested: { b: 2 } }; const deepCopy = structuredClone(original); deepCopy.nested.b = 42; console.log(original.nested.b); // 2 (Original remains untouched)JSON.parse(JSON.stringify())(Legacy Approach): This method serializes the object to a JSON string and parses it back into a new object.const deepCopy = JSON.parse(JSON.stringify(original));Limitations: It cannot handle functions,
undefined,Symbol,BigInt,Dateobjects (converted to strings),RegExp, or circular references.External Libraries (e.g., Lodash
cloneDeep): For complex edge cases or older environments lackingstructuredClone:import cloneDeep from 'lodash/cloneDeep'; const deepCopy = cloneDeep(original);
Summary of Differences
| Feature | Shallow Copy | Deep Copy |
|---|---|---|
| Top-Level Properties | Copied by value | Copied by value |
| Nested Objects/Arrays | Copied by reference (shared) | Copied by value (fully duplicated) |
| Performance | Fast and memory-efficient | Slower; consumes more memory for large trees |
| Mutation Risk | Nested changes affect the original | Completely isolated; zero side effects |
| Best Used For | Flat objects or read-only nested data | Complex nested state (e.g., Redux, React state) |