How to solve the problem of circular references in JavaScript deep and shallow copy

Introducing the deep and shallow copy of JavaScript

Deep copy and shallow copy in JavaScript are two different ways to copy objects and arrays .

Shallow copy refers to creating a new object or array. The new object/array only copies the reference value of the original object/array, but does not copy its internal sub-objects/array . In other words, 浅拷贝只复制了对象/数组的第一层,而不会递归地复制嵌套的对象/数组.

Deep copy refers to creating a new object or array. The new object/array copies all values ​​of the original object/array , including its internal sub-objects/arrays, and recursively copies all nested objects/arrays.

How to implement shallow copy

Shallow copy refers to creating a new object or array. The new object/array only copies the reference value of the original object/array, but does not copy its internal sub-objects/array.

Here are several common ways to implement shallow copies:

  1. Spread Operator: Shallow copy can be achieved using the spread operator (…).
const originalObj = {
    
     a: 1, b: 2 };
const shallowCopy = {
    
     ...originalObj };
  1. Object.assign() method: The Object.assign() method can copy the properties of the original object to a new object to achieve shallow copy.
const originalObj = {
    
     a: 1, b: 2 };
const shallowCopy = Object.assign({
    
    }, originalObj);
  1. Array.prototype.slice() method: For arrays, you can use the slice() method to copy the contents of the original array to achieve shallow copy.
const originalArr = [1, 2, 3];
const shallowCopy = originalArr.slice();
  1. Array.prototype.concat() method: Use the concat() method to connect the contents of the original array to a new array to achieve shallow copy.
const originalArr = [1, 2, 3];
const shallowCopy = [].concat(originalArr);
  1. Array.from() method: Use the Array.from() method to convert an array-like object or iterable object into an array and implement a shallow copy.
const originalArr = [1, 2, 3];
const shallowCopy = Array.from(originalArr);

These methods can create shallow copies of the original object or array. It should be noted that if the original object/array contains a sub-object/array of reference type, the shallow copy only copies the reference value, and modifying the shallow-copied object/array will also affect the original object/array. If you need to copy a sub-object/array, consider using deep copy.

How to implement deep copy

A deep copy means creating a new object that has the same values ​​as the original object but is completely independent in memory. There are several ways to implement deep copy:

  1. Manual copying : For simple objects, this is a pass 手动复制每个属性来实现深拷贝. But this approach can become tedious and error-prone, especially when objects are deeply nested.

  2. JSON serialization and deserialization : using JSON 序列化和反序列化is a convenient deep copy method. By converting an object to a JSON string, and then converting the string back into an object, you create an exact copy of the original object.

  3. Serialization and deserialization libraries : Many programming languages ​​provide specialized 序列化和反序列化libraries, such as the pickle module in Python, the Serializable interface in Java, etc. These libraries can make deep copies between objects, preserving the complete structure of the original objects.

  4. Using reflection and recursion : 使用反射可以遍历对象的所有属性,并为每个属性创建一个完全独立的副本. If the object's properties are still complex objects, you can use recursion to implement a deep copy of the sub-object.

No matter which method you choose, you need to determine the most appropriate implementation based on the specific programming language and scenario . Deep copy is an important technology to protect the data integrity of the original object, ensuring that the original object will not be affected when the copy is modified.

What issues need to be paid attention to when implementing deep copy?

When implementing deep copy, there are some issues that need to be paid attention to:

  1. Circular references循环引用(例如对象A引用对象B,对象B又引用对象A) : A deep copy can get stuck in an infinite loop if there are objects between them . When implementing deep copy, you need to handle the situation of circular references and take appropriate measures to break the cycle.

  2. Prototype chain : An object's prototype properties may contain functions or other mutable objects that may be difficult to deep copy accurately. When implementing deep copying, properties in the prototype chain need to be carefully handled to ensure the integrity of the copy.

  3. Symbol properties and non-enumerable properties : Objects may contain properties of type Symbol or non-enumerable properties, which may be ignored during the deep copy process. To achieve a complete deep copy, you need to ensure that Symbol properties and non-enumerable properties are also copied correctly.

  4. Performance issues : Deep copies may involve recursion and large amounts of object copying, which may cause performance issues, especially for complex objects or objects with deep nesting levels. In practical use, the appropriate balance needs to be weighed between the need for deep copies and the performance overhead.

These issues generally require attention when actually implementing deep copies, ensuring that the copied objects are complete, without unexpected side effects, and handling edge cases.

How to solve the problem of circular references

Circular references are a common problem in deep copies and can be solved by:

  1. Use a hash table to track copied objects : During the deep copy process, a hash table is maintained to store copied objects and corresponding copies. When copying an object, first check whether a copy of the object already exists in the hash table. If it exists, directly return the reference of the copy without performing a recursive copy.

  2. Use a variable to track copied objects : During the deep copy process, you can use a variable to track copied objects. When copying an object, store the object in a variable and make judgments when recursively copying other attributes. When encountering an object that has been copied, the previously copied reference is directly used.

The following is an example code that uses a hash table to solve the circular reference problem:

function deepCopy(obj, hash = new WeakMap()) {
    
    
    // 如果是基本类型或 null,则直接返回
    if (obj === null || typeof obj !== 'object') {
    
    
        return obj;
    }

    // 如果是已经拷贝过的对象,则返回拷贝的引用
    if (hash.has(obj)) {
    
    
        return hash.get(obj);
    }

    // 根据对象类型进行拷贝
    let newObj = Array.isArray(obj) ? [] : {
    
    };

    // 将当前对象存储到哈希表中
    hash.set(obj, newObj);

    // 递归拷贝对象的每个属性
    for (let key in obj) {
    
    
        if (obj.hasOwnProperty(key)) {
    
    
            newObj[key] = deepCopy(obj[key], hash);
        }
    }

    return newObj;
}

In this example, the WeakMap provided by ES6 is used as a hash table to store the copied objects. When using it, you only need to call deepCopy(obj)the method to perform deep copy. It will return a completely independent copy object, solving the problem of circular reference. Please note that this example is just one way to solve the circular reference problem, and the specific implementation may vary depending on the language and scenario.

Guess you like

Origin blog.csdn.net/m0_49768044/article/details/132462870