Deep Copy and Shallow Copy in JavaScript
Description
In JavaScript, deep copy and shallow copy are two different approaches for copying objects. A shallow copy only copies the reference to an object, not the object itself, meaning both the original and the new object share the same memory address. A deep copy creates a completely new object and recursively copies all properties of the original object, making the original and the new object entirely independent of each other. Understanding the difference between these two copying methods is crucial for avoiding unintended data modifications.
Knowledge Explanation
1. Distinguishing Basic Concepts
- Shallow Copy: Only copies the first layer of properties; if a property is a reference type, only the memory address is copied.
- Deep Copy: Completely copies the entire object structure, including all nested reference-type properties.
2. Comparison: Assignment, Shallow Copy, and Deep Copy
Let's first create a test object:
const originalObj = {
name: "小明",
age: 20,
hobbies: ["篮球", "游泳"],
address: {
city: "北京",
district: "海淀区"
}
};
Assignment Operation (Not a Copy):
const assignedObj = originalObj;
assignedObj.name = "小红";
console.log(originalObj.name); // "小红" - The original object is also modified.
3. Implementation Methods for Shallow Copy
Method 1: Object.assign()
const shallowCopy1 = Object.assign({}, originalObj);
shallowCopy1.name = "小刚"; // Modifying a primitive-type property
console.log(originalObj.name); // "小明" - The original object is unaffected.
shallowCopy1.hobbies.push("读书"); // Modifying a nested reference-type property
console.log(originalObj.hobbies); // ["篮球", "游泳", "读书"] - The original object is affected!
Method 2: Spread Operator
const shallowCopy2 = {...originalObj};
shallowCopy2.address.city = "上海";
console.log(originalObj.address.city); // "上海" - The original object is affected!
4. Implementation Methods for Deep Copy
Method 1: JSON.parse(JSON.stringify()) (Simplest but with limitations)
const deepCopy1 = JSON.parse(JSON.stringify(originalObj));
deepCopy1.hobbies.push("绘画");
console.log(originalObj.hobbies); // ["篮球", "游泳"] - The original object is unaffected.
Limitations:
const problemObj = {
date: new Date(),
func: function() {},
undefined: undefined,
infinity: Infinity,
regex: /abc/gi
};
const problematicCopy = JSON.parse(JSON.stringify(problemObj));
console.log(problematicCopy);
// Date becomes a string, function and undefined are lost, Infinity becomes null.
Method 2: Manually Written Recursive Deep Copy Function
function deepClone(obj, hash = new WeakMap()) {
// Handle primitive types and null
if (obj === null || typeof obj !== "object") {
return obj;
}
// Handle circular references
if (hash.has(obj)) {
return hash.get(obj);
}
// Handle Date objects
if (obj instanceof Date) {
return new Date(obj);
}
// Handle RegExp objects
if (obj instanceof RegExp) {
return new RegExp(obj);
}
// Handle arrays
if (Array.isArray(obj)) {
const result = [];
hash.set(obj, result);
obj.forEach(item => {
result.push(deepClone(item, hash));
});
return result;
}
// Handle plain objects
const result = {};
hash.set(obj, result);
Object.keys(obj).forEach(key => {
result[key] = deepClone(obj[key], hash);
});
return result;
}
5. Testing the Deep Copy Function
const testObj = {
name: "测试",
nested: {
array: [1, 2, { value: 3 }]
}
};
// Create a circular reference
testObj.self = testObj;
const clonedObj = deepClone(testObj);
clonedObj.nested.array.push(4);
console.log(testObj.nested.array); // [1, 2, {value: 3}] - The original object is unaffected.
console.log(clonedObj.self === clonedObj); // true - Circular reference handled correctly.
6. Practical Application Scenarios
Situations Suitable for Shallow Copy:
- Simple object structure with no nested reference types.
- Only need an independent copy of the first-layer properties.
- High performance requirements, large data volume.
Situations Suitable for Deep Copy:
- Need a completely independent object copy.
- Complex object structure with multiple nested layers.
- Need to modify the copy without affecting the original object.
Summary
Deep copy and shallow copy are important concepts in JavaScript. In actual development, the appropriate copying method should be chosen based on specific needs. For simple scenarios, the JSON method can be used; for complex scenarios, it is recommended to use mature utility libraries (such as Lodash's _.cloneDeep) or implement a complete deep copy function yourself.