JS深拷贝


拷贝的对象可能是多层级的,要确保深层嵌套也一样,可以使用递归,所以:

  • 如果是原始类型 =》 直接返回,无需继续拷贝。
  • 如果是引用类型 =》 创建新对象,遍历要克隆的对象&将对象属性深拷贝后依次放入新对象中。
完善过程:(最终版拉到最后
  1. 未考虑数组的情况下
export function basicClone(target) {
  // 先判断是否为对象类型:
  if (typeof target === 'object') {
    let cloneTarget = {};
    for (const key in target) {
      // 将原对象中每一项放入新对象:
      cloneTarget[key] = basicClone(target[key]);
    }
    // 返回新对象:
    return cloneTarget;
  } else {
    return target;
  }
}
  1. 根据以上改进加入数组
export function Clone(target) {
  if (typeof target === 'object') {
    // 关键:如果target是数组则定义个新数组而非对象。其余代码与上种无差别。
    let cloneTarget = Array.isArray(target) ? [] : {};
    for (const key in target) {
      cloneTarget[key] = Clone(target[key]);
    }
    return cloneTarget;
  } else {
    return target;
  }
}
  1. 考虑栈溢出的情况:(当对象中的属性引用了自身,进入死循环会导致栈溢出。)

    1. 解决循环引用:开辟新的存储空间放置当前对象和拷贝对象的对应关系。

      1. 当需要拷贝当前对象时先去存储空间找。有拷贝过这个对象 =》直接返回;
      2. 没有的话 =》继续拷贝。
    2. Map数据结构:https://juejin.cn/post/7064479924757168165。

// 测试用例:
const target = {
  field1: 1,
  field2: undefined,
  field3: {
      child: 'child'
  },
  field4: [2, 4, 8]
};
target.target = target;  // 这里导致栈溢出。


export function deepClone(target, map = new Map) {
  if (typeof target === 'object') {
    let cloneTarget = Array.isArray(target) ? [] : {};
    // 判断map中有没有已经克隆过的对象:
    if (map.get(target)) {
      // 有 =》直接返回:
      return map.get(target);
    }
    // 没有 =》将当前对象作为key,克隆对象作为value进行存储:
    map.set(target, cloneTarget);
    // 继续克隆:
    for (const key in target) {
      cloneTarget[key] = deepClone(target[key], map);
    }
    return cloneTarget;
  } else {
    return target;
  }
}

待完善,

关于WeakMap及其它拓展暂未学习。

参考:https://juejin.cn/post/6844903929705136141


文章作者: polariis
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 polariis !
评论
  目录