Personal blog posts: Daily Web front end questions (2021.05)
Shallow copy
If the property of the shallow-copied object is of reference type, it still points to the property of the same name of the source object. If you modify the properties under the reference type of the shallow-copy object, the source object is also modified. The implementation schemes are as follows:
{... obj}
Object.assign({}, obj)
for... in
Iterate over the object to get the key and place it in a new empty object.
Deep copy
If the properties under the reference type attribute are modified, the source object does not change. A real parting of the ways. Implementation of serialization and deserialization, and recursive implementation.
Serialize and deserialize
JSON. Parse (JSON. Stringify ()). The disadvantage is that:
- Copying special objects, such as Date and RegExp, causes problems
- Cannot handle looped objects, an error is reported
- If two properties point to the same object, the two namesake properties of the new object point to their respective properties
Manual implementation
The idea is to iterate over attributes, recursively for attributes of reference type, until all attributes are not reference types.
Problems to be solved:
- A circular reference is an attribute under an object that points to that object. If you recurse without special processing, an infinite loop will occur. To deal with the problem of ring, hash table is usually used to solve the problem: put the traversed object into the hash table (key is the source object, value is the new object), check whether the hash table has this object before copying, if there is a ring, directly take the corresponding value as the new object.
- Same reference, that is, multiple properties pointing to the same object. A circular reference is a special case of the same reference. The solution is to handle circular references.
- Special objects, ordinary objects, arrays these two most basic needless to say, JS built-in objects such as Date, RegExp should be targeted to do one by one processing. If user-defined objects need to be considered, they should also be dealt with in a targeted manner, such as adding prototype chain and implementing clone method in a targeted manner.
The implementation code is as follows (a simple unit test for each case) :
/** * Object deep copy * currently only supports normal objects and arrays ** handles the problem of circular references and identical references **@param {any} Obj The object to be copied *@returns A new object * /
const cloneDeep = (obj) = > {
const map = new Map(a)// oldObj -> newObj
function _cloneDeep(obj) {
if (obj === null || typeofobj ! = ='object') return obj // Non-object value
if (map.has(obj)) { // Check for the same reference
return map.get(obj)
}
const retObj = Array.isArray(obj) ? [] : {} // Determine whether the carrier of the new object is a normal object or an array.
// This line must be placed here, not in front of return. This is to handle "circular reference" cases
// The loop object must already be in the map when it is found, otherwise it will loop forever.
map.set(obj, retObj)
for (const key in obj) { // Iterate over attributes
retObj[key] = _cloneDeep(obj[key])
}
return retObj
}
return _cloneDeep(obj)
}
Copy the code
In practice, you don’t need an overly sophisticated deep copy; serialization and deserialization are generally sufficient. If the situation is a bit complicated, consider using loadsh.clonedeep