详细代码: code demo

异同:

浅复制 (影子克隆): 只复制对象的基本类型, 对象类型, 仍属于原来的引用。
深复制 (深度克隆): 不紧复制对象的基本类, 同时也复制原对象中的对象。就是说完全是新对象产生的。

思路:

遍历所有该对象的属性,
如果该属性是 "object" 则需要特殊处理,
如果这个 object 对象比较特殊,是一个数组,那就创建一个新的数组并深复制数组里的元素
如果这个 object 对象是个非数组对象,那直接再对它递归调用深复制方法即可。
如果不是 "object",则直接正常复制就行。

对象的拷贝实现

浅拷贝

const obj = {
    a:10,
    b:{
        c:'ccc'
    }
};
// 方法一:Object.assign
const a={};
Object.assign(a,obj);

//方法二:对象解构
const a = {...obj,{}}

深拷贝

function deepCopy(obj){
    // object
    if(typeof obj === 'object'){
      // 排除null;
      if(obj === null){
          return null;
      }
      // array
      if(Array.isArray(obj)){
          const newArr = [];
          for(let i=0;i<obj.length;i++){
              const item = deepCopy(obj[i]);
              newArr.push(item);
          }
          return newArr;
      }
      // other->object
      const keys = Object.keys(obj);
      const tempObj = {};
      for(let key of keys){
          const v = obj[key];
          tempObj[key] = deepCopy(v);
      }
      return tempObj;
    }else{
      return obj;
    }
};

测试

const mock = ({
    a:'111',
    b:[1,2,3,4,5,{
        s:null,
        ss:undefined,
        sss:[111]
    }],
    c:{
        cc:{
            ccc:'2222'
        },
        ccc02:[555],
    }
});

// test
const r = deepCopy(mock);
r.b.s = 'new s value'; // r.b.s =>'new s value'; mock.b.s => null

更完整的实现(支持 Map Set Symbol)

  1. 这一版实现修复了 Date、RegExp 的复制能力,上一版按照 object 直接复制会丢失他们的一些属性(不可枚举)
  2. 支持 Map、Set
  3. 支持 Symbol
function deepClone(target, map = new WeakMap()) {
  // 1. 基本数据类型,直接返回
  if (target === null || typeof target !== 'object') {
    return target;
  }

  // 2. 日期对象
  if (target instanceof Date) {
    return new Date(target);
  }

  // 3. 正则对象
  if (target instanceof RegExp) {
    return new RegExp(target);
  }

  // 4. Map 处理
  if (target instanceof Map) {
    const cloneMap = new Map();
    map.set(target, cloneMap); // 缓存,防止循环引用
    target.forEach((value, key) => {
      // 注意:Map 的 key 也可能是引用类型,所以 key 也需要深拷贝
      cloneMap.set(deepClone(key, map), deepClone(value, map));
    });
    return cloneMap;
  }

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

  // 6. 处理循环引用
  // 注意:因为上面已经处理了 Map/Set 并放入了 map,这里不会重复处理
  if (map.has(target)) {
    return map.get(target);
  }

  // 7. 初始化克隆对象 (数组或对象)
  const cloneTarget = Array.isArray(target) ? [] : Object.create(Object.getPrototypeOf(target));
  
  map.set(target, cloneTarget);

  // 8. 遍历对象属性,递归拷贝
  for (let key in target) {
    if (target.hasOwnProperty(key)) {
      cloneTarget[key] = deepClone(target[key], map);
    }
  }

  // 9. 处理 Symbol 属性
  const symbolKeys = Object.getOwnPropertySymbols(target);
  for (let i = 0; i < symbolKeys.length; i++) {
    const key = symbolKeys[i];
    if (target.propertyIsEnumerable(key)) {
      cloneTarget[key] = deepClone(target[key], map);
    }
  }

  return cloneTarget;
}

specialcoder
2.2k 声望172 粉丝

前端 设计 摄影 文学