深拷贝如何实现

JavaScript 深拷贝实现方法大全

深拷贝是指创建一个新对象,并递归复制原对象的所有属性,使得新对象与原对象完全独立,修改新对象不会影响原对象。以下是多种深拷贝的实现方式:

一、JSON 方法(最简单但有局限)

function deepCopy(obj) {
  return JSON.parse(JSON.stringify(obj));
}

特点

  • ✅ 简单快捷

  • ❌ 不能复制函数、Symbol、undefined

  • ❌ 不能处理循环引用

  • ❌ 会丢失对象的原型链

适用场景:简单的数据对象拷贝

二、递归实现(基础版)

function deepCopy(obj) {
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }
  
  let copy = Array.isArray(obj) ? [] : {};
  
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      copy[key] = deepCopy(obj[key]);
    }
  }
  
  return copy;
}

三、递归实现(增强版)

处理更多边界情况:

function deepCopy(obj, hash = new WeakMap()) {
  // 处理基本类型和null
  if (obj === null || typeof obj !== 'object') return obj;
  
  // 处理循环引用
  if (hash.has(obj)) return hash.get(obj);
  
  // 处理Date
  if (obj instanceof Date) return new Date(obj);
  
  // 处理RegExp
  if (obj instanceof RegExp) return new RegExp(obj);
  
  // 处理Set
  if (obj instanceof Set) {
    const copy = new Set();
    hash.set(obj, copy);
    obj.forEach(value => copy.add(deepCopy(value, hash)));
    return copy;
  }
  
  // 处理Map
  if (obj instanceof Map) {
    const copy = new Map();
    hash.set(obj, copy);
    obj.forEach((value, key) => copy.set(key, deepCopy(value, hash)));
    return copy;
  }
  
  // 处理数组或普通对象
  const copy = Array.isArray(obj) ? [] : Object.create(
    Object.getPrototypeOf(obj)
  );
  
  hash.set(obj, copy);
  
  // 处理Symbol属性
  const symKeys = Object.getOwnPropertySymbols(obj);
  for (const symKey of symKeys) {
    copy[symKey] = deepCopy(obj[symKey], hash);
  }
  
  // 处理普通属性
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      copy[key] = deepCopy(obj[key], hash);
    }
  }
  
  return copy;
}

四、使用第三方库

1. lodash 的 _.cloneDeep

import _ from 'lodash';
const copied = _.cloneDeep(original);

2. jQuery 的 $.extend

const copied = $.extend(true, {}, original);

五、MessageChannel(异步深拷贝)

function deepCopy(obj) {
  return new Promise(resolve => {
    const { port1, port2 } = new MessageChannel();
    port2.onmessage = ev => resolve(ev.data);
    port1.postMessage(obj);
  });
}

// 使用
const copied = await deepCopy(original);

特点

  • ✅ 可以处理循环引用

  • ❌ 异步操作

  • ❌ 不能复制函数

六、structuredClone API(现代浏览器)

const copied = structuredClone(original);

特点

  • ✅ 浏览器原生方法

  • ✅ 处理循环引用

  • ❌ 不能复制函数、DOM节点等

  • ❌ IE不支持

七、性能对比

方法函数Symbol循环引用性能
JSON★★★★
递归★★
lodash★★★
MessageChannel★★
structuredClone★★★★

八、实际应用建议

  1. 简单数据对象:使用 JSON.parse(JSON.stringify())

  2. 需要完整拷贝:使用 lodash 的 _.cloneDeep

  3. 现代浏览器环境:尝试 structuredClone

  4. 特殊需求:根据需求选择或自定义递归实现

九、循环引用处理示例

const obj = { a: 1 };
obj.self = obj; // 循环引用

// 使用WeakMap处理循环引用的深拷贝
function deepCopy(obj, hash = new WeakMap()) {
  if (hash.has(obj)) return hash.get(obj);
  
  let copy = Array.isArray(obj) ? [] : {};
  hash.set(obj, copy);
  
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      copy[key] = deepCopy(obj[key], hash);
    }
  }
  
  return copy;
}

const copied = deepCopy(obj);
console.log(copied.self === copied); // true

选择深拷贝方法时,应根据实际需求考虑数据类型、性能要求和运行环境等因素。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值