SOURCE

/**
 * @desc 深拷贝函数
*/

function cloneDeep(obj, cache = new WeakMap()) {
    // 如果该变量为非对象类型直接返回
    if (obj === null || typeof obj !== 'object') {
        return obj
    }
    // 如果是复杂类型,Date、RegExp类型的对象需要特殊处理下
    if (obj instanceof Date) {
        return  new Date(obj);
    }
    if (obj instanceof RegExp) {
        return new RegExp(obj);
    }
    // 特别注意循环引用的情况 a = {}; a.b = a; 为了避免这种情况,引入一个WeakMap来存储
    if (cache.has(obj)) {
        return cache.get(obj);
    }
    // 正常的处理情况,使用for... in遍历对象的key
    // 创建一个新的空对象,为了保证原型链,调用一下构造函数
    const cloneObj = new obj.constructor();

    // 创建过的对象,往WeakMap中存一下
    cache.set(obj, cloneObj);

    for (key in obj) {
        if (obj.hasOwnProperty(key)) {
            // 属性有可能是对象类型,所以需要递归处理
            cloneObj[key] = cloneDeep(obj[key], cache);
        }
    }
    return cloneObj;
}

function deepClone(obj, cache = new WeakMap()) {
  if (obj === null || typeof obj !== 'object') return obj
  if (obj instanceof Date) return new Date(obj)
  if (obj instanceof RegExp) return new RegExp(obj)
  
  if (cache.has(obj)) return cache.get(obj) // 如果出现循环引用,则返回缓存的对象,防止递归进入死循环
  let cloneObj = new obj.constructor() // 使用对象所属的构造函数创建一个新对象
  cache.set(obj, cloneObj) // 缓存对象,用于循环引用的情况

  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      cloneObj[key] = deepClone(obj[key], cache) // 递归拷贝
    }
  }
  return cloneObj
}

// 测试
const obj = { name: 'Jack', address: { x: 100, y: 200 } }
obj.a = obj // 循环引用
const newObj = cloneDeep(obj)
console.log(newObj.address === obj.address) // false
console 命令行工具 X clear

                    
>
console