手写深拷贝

78 阅读1分钟

因为JSON实现的深拷贝不能满足特殊需求

const weakMap = new WeakMap();
function deepClone(origin) {
  // 判断是否为Set类型
  if (origin instanceof Set) return new Set([...origin]);
  // 判断是否为Map类型
  if (origin instanceof Map) return new Map([...origin])
  // 如果是Symbol作为的value则创建一个新Symbol并返回
  if (typeof origin == 'symbol') return Symbol(origin.description);
  // 如果是函数类型则直接使用这个函数(因为函数的逻辑本来就是用来复用的)
  if (typeof origin == 'function') return origin;
  // 当值不是个object则直接返回(无需深拷贝)
  if (!isObject(origin)) return origin;
  // 解决对象循环引用
  if (weakMap.has(origin)) return weakMap.get(origin);

  // 根据当前赋值数据类型创建不同的存储容器
  const newVariable = Array.isArray(origin) ? [] : {};
  // 记录本对象
  weakMap.set(origin, newVariable);

  // 迭代复杂数据类型并存入对应容器(当是数组时key就是下标、是对象时key就是key)[新值的值是本函数返回的]
  for (const key in origin) newVariable[key] = deepClone(origin[key])
  // 对使用Symbol作为key的特殊处理(这里需要用of不然拿到的是索引)[因为getOwn返回的是个数组]
  for (const key of Object.getOwnPropertySymbols(origin)) newVariable[key] = deepClone(origin[key]);

  // 每次执行完毕删除对应key
  weakMap.delete(origin);

  // 最后一次返回给外界
  return newVariable;
};
// 判断是否是object类型的工具函数
function isObject(value) {
  const valueType = typeof value;
  // function本质上也是个object
  return (value !== null) && (valueType == 'object' || valueType == 'function')
}

const s1 = Symbol('111');
const s2 = Symbol('222');

const obj = {
  name: '苏苏',
  age: 18,
  friends: ['土狗', 'SharkDog'],
  miss: {
    name: '安安',
    age: 16
  },
  [s1]: 'sss',
  s2,
  set: new Set([1, 2, 3]),
  map: new Map([[1, 2], ['a', 'b']]),
};
obj.test = obj;

const newObj = deepClone(obj);

obj.miss.name = 'test';
obj.friends[0] = 'test';

console.log(obj);
console.log(newObj);