Deep clone in JavaScript means creating a complete copy of an object, and all nested objects in the copy are also copied, rather than just referring to nested objects in the original object. The main difference between deep cloning and shallow cloning is that shall only copy references to the object, while deep cloning recursively copies data at all levels in the object.
Why deep cloning is needed
In some complex applications, especially when it comes to immutable data structures, we need to modify the object without affecting the original object. For example, state management in React, data binding in Vue, or state update in Redux.
Common deep cloning methods
Method 1: Use the JSON method
The most common way to implement deep cloning is through () and (). This approach is very easy, but it has some limitations and potential drawbacks:
const originalObj = { name: 'Alice', address: { city: 'Wonderland', postalCode: '12345' } }; const clonedObj = ((originalObj)); (clonedObj); // { name: 'Alice', address: { city: 'Wonderland', postalCode: '12345' } }
advantage:
Simple and easy to understand, the code is very concise.
shortcoming:
- Functions, undefined, Symbol, Date and other types cannot be cloned.
- Loop references in the object are lost and the loop structure cannot be processed.
- Special properties such as prototype chain, getter/setter, etc. in the object will be ignored.
Method 2: Manual recursive cloning
For objects that need to deal with more complex structures, a recursive deep cloning function can be implemented:
function deepClone(obj) { if (obj === null || typeof obj !== 'object') { return obj; // If it is a primitive type, return directly } // Handle special cases: Date and RegExp and other types if (obj instanceof Date) { return new Date(obj); //Clone the Date object } if (obj instanceof RegExp) { return new RegExp(obj); //Clone RegExp object } // Process arrays and objects const clonedObj = (obj) ? [] : {}; for (const key in obj) { if ((key)) { clonedObj[key] = deepClone(obj[key]); // Recursively cloning each property } } return clonedObj; } const originalObj = { name: 'Bob', age: 30, dateOfBirth: new Date('1994-12-25'), address: { city: 'New York', zip: '10001' }, hobbies: ['reading', 'coding'], greet: function() { ('Hello'); } }; const clonedObj = deepClone(originalObj); (clonedObj); ( instanceof Date); // true ( === ); // false
advantage:
- Supports multiple data types (including Date and RegExp).
- Ability to handle circular references (extra processing is required).
- Can be customized as needed.
shortcoming:
- Different types of objects need to be processed manually, and the code is complicated.
- If there is a circular reference in the object, it may cause stack overflow.
Method 3: Use StructuredClone (supported by modern browsers)
StructuredClone is a browser natively supported method that can clone objects and their internal structures, including Date, Map, Set, ArrayBuffer, etc. But it still doesn't support functions or some special objects (such as RegExp).
const originalObj = { name: 'Charlie', birthdate: new Date('1992-05-15'), hobbies: ['running', 'painting'], meta: new Map([['key', 'value']]) }; const clonedObj = structuredClone(originalObj); (clonedObj); ( instanceof Date); // true ( instanceof Map); // true ( === ); // false
advantage:
- Modern browsers have built-in support and simple code.
- Supports more data types (such as Map, Set, ArrayBuffer, Date, etc.).
shortcoming:
Not all JavaScript environments support structuredClone, for example, not in some older browsers or in some old versions.
Method 4: Use a third-party library
Third-party libraries often provide very powerful and reliable deep cloning capabilities, such as Lodash's cloneDeep method. It can handle most complex situations, including circular references.
// Use lodashimport cloneDeep from 'lodash/cloneDeep'; const originalObj = { name: 'David', hobbies: ['sports', 'music'], meta: new Map([['key', 'value']]) }; const clonedObj = cloneDeep(originalObj); (clonedObj); ( === ); // false
advantage:
- Process complex data structures (including circular references, Map, Set, etc.).
- After extensive testing, it is stable and reliable.
shortcoming:
It is necessary to introduce third-party libraries to increase project dependencies.
Application in actual projects
Suppose you are developing an application and need to deep clone the state of an object, such as managing the state in Redux or Vuex:
// Assume this is your state objectconst state = { user: { name: 'Alice', preferences: { theme: 'dark', language: 'en', }, }, isAuthenticated: true, }; // Use deep cloning to avoid direct modification of the original stateconst newState = deepClone(state); // Modifying the new state will not affect the original state = 'light'; (); // 'dark' (); // 'light'
In this example, deep cloning ensures that we do not change the original state object, thus avoiding unnecessary side effects. This is particularly important for managing application states, especially when the state is immutable.
Summarize
The JSON method is suitable for deep cloning of simple objects, but does not support functions, dates, regular expressions, etc.
Manual recursive cloning is the most flexible way to handle multiple types, but requires writing additional code.
**structuredClone** is a native method in modern browsers that supports more data types, but has poor compatibility.
**Third-party libraries (such as Lodash)** provide reliable deep cloning implementations for complex applications, but increase project dependencies.
In actual projects, choose the appropriate method according to your needs. If your project has fewer dependencies and needs to deal with complex data types, manually implementing or using structuredClone is a good choice. If you are dealing with very complex objects and you are willing to introduce external dependencies, it will be more convenient to use libraries such as Lodash.
This is the end of this article about how to perform deep cloning in JavaScript. For more related JavaScript deep cloning content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!