In JavaScript, Object.assign() is a common method for combining object properties. However, for many developers there may be some confusion as to whether it performs a deep copy or not. Let’s start by saying that the answer Object.assign()
does not belong to deep copy, let’s look down.
Object.assign() Overview
First, let’s review Object.assign()
the basic usage of . This method is used to copy the properties of one or more source objects to the target object and return the target object. This process is a shallow copy, that is, for nested objects or arrays, only the reference is copied rather than creating a new object.
const obj = { a: 1, b: { c: 2 } };
const obj2 = { d: 3 };
const mergedObj = Object.assign({}, obj, obj2);
console.log(mergedObj);
// output: { a: 1, b: { c: 2 }, d: 3 }
Shallow copy pitfalls
The shallow copy feature means that if the source object contains objects or arrays, their references will be copied to the new object. This can cause problems, especially when modifying new objects, the original objects are also affected.
const obj = { a: 1, b: { c: 2 } };
const clonedObj = Object.assign({}, obj);
clonedObj.b.c = 3;
console.log(obj); // { a: 1, b: { c: 3 } }
console.log(clonedObj); // { a: 1, b: { c: 3 } }
In this example, the modified clonedObj
properties also affect the original object obj
.
Therefore, if we need to create a completely new and independent copy of the original object, we need to make a deep copy. Object.assign() does not provide deep copy function.
Deep copy requirements
If you need to do a deep copy instead of just a shallow copy, you need to use other methods, such as using recursion or a third-party library to implement deep copy. The following are several common deep copy methods:
1. Use JSON serialization and deserialization
const obj = { a: 1, b: { c: 2 } };
const deepClonedObj = JSON.parse(JSON.stringify(obj));
deepClonedObj.b.c = 3;
console.log(obj); // { a: 1, b: { c: 2 } }
console.log(deepClonedObj); // { a: 1, b: { c: 3 } }
This method takes advantage of the JSON serialization and deserialization process to implement a new deep copy object by converting the object to a string and then converting the string back to the object.
It should be noted that this method has some limitations, such as the inability to handle objects containing circular references, and some special objects (such as RegExp objects) may lose information during serialization and deserialization.
2. Use recursion to implement deep copy
function deepClone(obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
const clonedObj = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
clonedObj[key] = deepClone(obj[key]);
}
}
return clonedObj;
}
const obj = { a: 1, b: { c: 2 } };
const deepClonedObj = deepClone(obj);
deepClonedObj.b.c = 3;
console.log(obj); // { a: 1, b: { c: 2 } }
console.log(deepClonedObj); // { a: 1, b: { c: 3 } }
This is a recursive method to implement deep copy. It recursively iterates over the object’s properties and creates copies of them. This method is relatively flexible and can handle various situations.
However, be aware that stack overflow may occur when dealing with large objects or deeply nested objects.
3. Use third-party libraries
Many third-party libraries provide powerful and flexible deep copy functions, the most commonly used of which is _.cloneDeep
the method in the lodash library.
const _ = require('lodash');
const obj = { a: 1, b: { c: 2 } };
const deepClonedObj = _.cloneDeep(obj);
deepClonedObj.b.c = 3;
console.log(obj); // { a: 1, b: { c: 2 } }
console.log(deepClonedObj); // { a: 1, b: { c: 3 } }
The advantage of using third-party libraries is that they are usually well designed and tested, can handle more edge cases, and provide better performance.