BRUCE_FEBRUCE_FE

EN/CH Mode

BRUCE_FE JS Interview Notes - Deep Copy vs Shallow Copy

In-depth analysis of deep and shallow copy mechanisms in JavaScript, including implementation principles, performance considerations, React application scenarios, and complete answers to common interview questions.

影片縮圖

Lazy to read articles? Then watch videos!

Basic Concepts

In JavaScript, different copying methods are used when assigning variables based on data types:

  • Primitive types: Direct value copying (number, string, boolean, null, undefined, symbol)
  • Reference types: Copy reference addresses (object, array, function)

Shallow Copy

Only copies the first level values; nested objects still share reference addresses. Common methods:

// 1. Object.assign()
const original = { name: 'Bruce', info: { age: 25 } };
const copy1 = Object.assign({}, original);

// 2. Spread operator
const copy2 = { ...original };

// 3. Array methods
const arr = [1, [2, 3]];
const arrCopy1 = Array.from(arr);
const arrCopy2 = arr.slice();

Deep Copy

Recursively copies values at all levels, creating completely independent new objects. Common methods:

// 1. structuredClone (recommended, but check browser support)
const deepCopy1 = structuredClone(original);

// 2. JSON methods (with limitations)
const deepCopy2 = JSON.parse(JSON.stringify(original));

// 3. Using Lodash library
// Install first: npm install lodash
import _ from 'lodash';
const deepCopy3 = _.cloneDeep(original);

// 4. Recursive implementation
function deepClone(obj) {
  if (obj === null || typeof obj !== 'object') return obj;
  
  const copy = Array.isArray(obj) ? [] : {};
  
  for (let key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      copy[key] = deepClone(obj[key]);
    }
  }
  
  return copy;
}

🔥 Common Interview Questions

(1) What's the difference between shallow copy and deep copy?

Answer:

const original = {
  name: 'Bruce',
  info: { age: 25 }
};

// Shallow copy
const shallow = { ...original };
shallow.info.age = 26;
console.log(original.info.age); // 26 - original object is modified

// Deep copy
const deep = structuredClone(original);
deep.info.age = 27;
console.log(original.info.age); // 26 - original object is not affected

(2) Why is JSON.parse(JSON.stringify()) not recommended for deep copying?

Answer: JSON methods have the following limitations:

const obj = {
  func: () => console.log('Hello'),
  symbol: Symbol('test'),
  undefined: undefined,
  date: new Date(),
  regexp: /test/,
  [Symbol('key')]: 'value'
};

const copy = JSON.parse(JSON.stringify(obj));
console.log(copy.func);      // undefined - functions are lost
console.log(copy.symbol);    // undefined - Symbols are lost
console.log(copy.undefined); // undefined - undefined values are lost
console.log(copy.date);      // string - no longer a Date object
console.log(copy.regexp);    // {} - regular expressions become empty objects
console.log(copy[Symbol('key')]); // undefined - Symbol keys are lost

(3) How to implement a deep copy function?

Answer:

function deepClone(obj) {
  if (obj === null || typeof obj !== 'object') return obj;
  
  const copy = Array.isArray(obj) ? [] : {};
  
  for (let key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      copy[key] = deepClone(obj[key]);
    }
  }
  
  return copy;
}
function deepClone2(value, hash = new WeakMap()) {
  // Handle null and non-objects
  if (value === null || typeof value !== 'object') return value;
  
  // Handle Date objects
  if (value instanceof Date) return new Date(value);
  
  // Handle RegExp objects
  if (value instanceof RegExp) return new RegExp(value);
  
  // Handle circular references
  if (hash.has(value)) return hash.get(value);
  
  // Create new array or object
  const copy = Array.isArray(value) ? [] : {};
  
  // Record processed objects to avoid circular references
  hash.set(value, copy);
  
  // Recursively process all properties
  Object.entries(value).forEach(([key, val]) => {
    copy[key] = deepClone(val, hash);
  });
  
  return copy;
}

// Usage example
const obj = {
  array: [1, { a: 2 }],
  date: new Date(),
  regexp: /test/,
  func: function() {},
  nested: {
    deep: { value: 123 }
  }
};

// Create circular reference
obj.self = obj;

const cloned = deepClone(obj);
console.log(cloned.nested.deep.value); // 123
console.log(cloned.self === cloned); // true - maintains circular reference
console.log(cloned.self !== obj); // true - is a new object