sakila1012 / blog

记录自己学习工作中的心得
10 stars 3 forks source link

如何实现一个深拷贝? #70

Open sakila1012 opened 3 years ago

sakila1012 commented 3 years ago

// 实现一个拷贝,实现一个递归拷贝

function deepClone(obj, hash = new WeakMap()){
  if(obj == null) return obj; // 如果是null或者undefined,就不进行拷贝操作
  if(obj instanceof Date) return new Date(obj);
  if(obj instanceof RegExp) return new RegExp(obj)
  // 可能是对象 或者普通的值,如果是函数的话,就不需要深拷贝
  if(typeof obj !== 'object') return obj;
  // 如果是对象就进行深拷贝
  if(hash.get(obj)) return hash.get(obj);
  let cloneObj = new obj.constructor;
  hash.set(obj, cloneObj);
  for(let key in obj) {
    if(obj.hasOwnProperty(key)) {
       cloneObj[key] = deepClone(obj[key])
    }
  }
  return cloneObj
}
function isObject (target) {
  const type = typeof target;
  return target !== null && (type === 'object' || type === 'function')
}

function deepClone(target, cache = new WeakSet()){
  if(!isObject(target)) return target; // 拷贝基本类型的值
  if(cache.has(target)) return target; // 如果之前已经拷贝过该对象,直接返回该对象
  cache.add(target) // 将对象添加到缓存

  let cloneTarget = Array.isArray(target) ? [] : {};
  Object.keys(target).forEach(key => {
    cloneTarget[key] = deepClone(target[key], cache)
  })
  return cloneTarget;
}

这里采用了WeakSet收集拷贝对象,WeakSet中的对象都是弱引用的,垃圾回收机制不考虑WeakSet。

上面的两个方法有啥区别呢,其实没啥区别,都是用WeakSet,WeakMap的弱引用功能,解决循环引用的问题。 我们可以开辟一个空间存储要拷贝的对象,当拷贝对象时,先去存储空间查找该对象是否被拷贝过,如果拷贝过,直接返回该对象,如果没拷贝过,就继承拷贝。