鲁斯前端布鲁斯前端

文章中英模式

布鲁斯前端JS面试题目 - 深拷贝与浅拷贝深入解析

深入解析 JavaScript 中的深拷贝与浅拷贝机制,包含实现原理、性能考量、React 应用场景,以及面试常见问题的完整解答。

影片縮圖

懒得看文章?那就来看视频吧

基本概念

在 JavaScript 中,变量赋值时会根据数据类型采用不同的复制方式:

  • 基本类型:直接复制值(number、string、boolean、null、undefined、symbol)
  • 引用类型:复制引用地址(object、array、function)

浅拷贝 (Shallow Copy)

只复制第一层的值,嵌套对象仍然共享引用地址。常见方法:

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

// 2. 展开运算符
const copy2 = { ...original };

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

深拷贝 (Deep Copy)

递归复制所有层级的值,创建完全独立的新对象。常见方法:

// 1. structuredClone (推荐,但需注意浏览器支持)
const deepCopy1 = structuredClone(original);

// 2. JSON 方法 (有限制)
const deepCopy2 = JSON.parse(JSON.stringify(original));

// 3. 使用 Lodash 函数库
// 需先安装: npm install lodash
import _ from 'lodash';
const deepCopy3 = _.cloneDeep(original);

// 4. 递归实现
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;
}

🔥 常见面试题目

(一)浅拷贝和深拷贝的区别?

解答:

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

// 浅拷贝
const shallow = { ...original };
shallow.info.age = 26;
console.log(original.info.age); // 26 - 原对象被修改

// 深拷贝
const deep = structuredClone(original);
deep.info.age = 27;
console.log(original.info.age); // 26 - 原对象不受影响

(二)为什么不建议使用 JSON.parse(JSON.stringify()) 进行深拷贝?

解答:JSON 方法有以下限制:

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 - 函数丢失
console.log(copy.symbol);    // undefined - Symbol 丢失
console.log(copy.undefined); // undefined - undefined 丢失
console.log(copy.date);      // 字符串 - 不再是 Date 对象
console.log(copy.regexp);    // {} - 正则表达式变成空对象
console.log(copy[Symbol('key')]); // undefined - Symbol key 丢失

(三)如何实现一个深拷贝函数?

解答:

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