Deep Copy and Shallow Copy in JavaScript

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.