deepClone

const OBJECT_TYPE = '[object Object]'
const ARRAY_TYPE = '[object Array]'
const MAP_TYPE = '[object Map]'
const SET_TYPE = '[object Set]'
const DEEP_TYPES = [OBJECT_TYPE, ARRAY_TYPE, MAP_TYPE, SET_TYPE]

const getType = (target: any) => Object.prototype.toString.call(target)

export default function deepClone(target: any, cache = new WeakMap()) {
  const type = getType(target)
  if (DEEP_TYPES.includes(type)) {
    // 通过构造函数初始化引用类型
    const cloneObj = new target.constructor()
    // 处理循环引用
    if (cache.has(target)) return cache.get(target)
    cache.set(target, cloneObj)

    if (type === ARRAY_TYPE) {
      target.forEach((v: any, index: number) => {
        cloneObj[index] = deepClone(v, cache)
      })
    }

    if (type === OBJECT_TYPE) {
      Object.entries(target).forEach(([k, v]) => {
        cloneObj[k] = deepClone(v, cache)
      })
    }

    if (type === MAP_TYPE) {
      target.forEach((v: any, k: any) => {
        cloneObj.set(k, deepClone(v, cache))
      })
    }

    if (type === SET_TYPE) {
      target.forEach((v: any) => {
        cloneObj.add(deepClone(v, cache))
      })
    }

    return cloneObj
  }

  return target
}