实现一个深拷贝函数(支持循环引用、Symbol、函数等特殊情况)

下面是一个完整的深拷贝实现,考虑了循环引用、Symbol、函数、Date、RegExp、Map、Set等特殊类型:

function deepClone(target, map = new WeakMap()) {
  // 处理原始类型和函数(函数直接返回,因为通常不需要拷贝)
  if (typeof target !== 'object' || target === null) {
    return target;
  }

  // 处理循环引用
  if (map.has(target)) {
    return map.get(target);
  }

  // 处理Date对象
  if (target instanceof Date) {
    return new Date(target);
  }

  // 处理RegExp对象
  if (target instanceof RegExp) {
    return new RegExp(target);
  }

  // 处理Map
  if (target instanceof Map) {
    const clone = new Map();
    map.set(target, clone);
    target.forEach((value, key) => {
      clone.set(deepClone(key, map), deepClone(value, map));
    });
    return clone;
  }

  // 处理Set
  if (target instanceof Set) {
    const clone = new Set();
    map.set(target, clone);
    target.forEach(value => {
      clone.add(deepClone(value, map));
    });
    return clone;
  }

  // 处理Symbol
  if (typeof target === 'symbol') {
    return Symbol(target.description);
  }

  // 处理数组和普通对象
  const clone = Array.isArray(target) ? [] : {};
  map.set(target, clone);

  // 处理Symbol作为key的情况
  const symKeys = Object.getOwnPropertySymbols(target);
  if (symKeys.length) {
    symKeys.forEach(symKey => {
      clone[symKey] = deepClone(target[symKey], map);
    });
  }

  // 处理普通key
  for (const key in target) {
    if (target.hasOwnProperty(key)) {
      clone[key] = deepClone(target[key], map);
    }
  }

  return clone;
}

关键点解析

循环引用处理:

使用WeakMap来存储已拷贝的对象,遇到相同的引用时直接返回存储的副本

特殊对象处理:

Date:创建新的Date实例

RegExp:创建新的RegExp实例

Map/Set:递归拷贝其内容

Symbol:创建新的Symbol,保持相同的description

函数处理:

函数直接返回原函数,因为通常不需要拷贝函数

Symbol作为key:

使用Object.getOwnPropertySymbols()获取Symbol key并递归拷贝

性能考虑:

使用WeakMap而不是Map,避免内存泄漏

只在必要时创建新对象

使用示例

const obj = {
  num: 1,
  str: 'hello',
  arr: [1, 2, 3],
  date: new Date(),
  reg: /abc/gi,
  fn: function() { console.log('function') },
  [Symbol('sym')]: 'symbol value',
  map: new Map([['key', 'value']]),
  set: new Set([1, 2, 3])
};

// 创建循环引用
obj.self = obj;

const cloned = deepClone(obj);
console.log(cloned);
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容