/**
 * 深拷贝
 * @param target 原生对象
 */
export function cloneDeep(target, cache = new WeakMap()) {
    // 值类型
    const undefinedTag = '[object Undefined]'
    const nullTag = '[object Null]'
    const boolTag = '[object Boolean]'
    const numberTag = '[object Number]'
    const stringTag = '[object String]'
    const symbolTag = '[object Symbol]'
    const bigIntTag = '[object BigInt]'
    // 引用类型
    const arrayTag = '[object Array]'
    const objectTag = '[object Object]'

    // 传入对象的类型
    const type = Object.prototype.toString.call(target)

    // 所有支持的类型
    const allTypes = [
        undefinedTag, nullTag, boolTag, numberTag, stringTag, symbolTag, bigIntTag, arrayTag, objectTag
    ]

    // 如果是不支持的类型
    if (!allTypes.includes(type)) {
        console.warn(`不支持${type}类型的拷贝，返回{}。`)
        return {}
    }

    // 值类型数组
    const valTypes = [
        undefinedTag, nullTag, boolTag, numberTag, stringTag, symbolTag, bigIntTag
    ]

    // 值类型直接返回
    if (valTypes.includes(type)) {
        return target
    }

    // forEach
    function forEach(array, iteratee) {
        let index = -1
        const length = array.length

        while (++index < length) {
            // 中断遍历
            if (iteratee(array[index], index, array) === false) {
                break
            }
        }
        return array
    }

    // 初始化clone值
    let cloneTarget = new target.constructor()
    // 阻止循环引用
    if (cache.has(target)) {
        return cache.get(target)
    }
    cache.set(target, cloneTarget)

    // 克隆Array 和Object
    const keys = type === arrayTag ? undefined : Object.keys(target)
    forEach(keys || target, (value, key) => {
        if (keys) {
            key = value
        }
        cloneTarget[key] = cloneDeep(target[key], cache)
    })

    return cloneTarget
}