// Determine whether the data type is complex
const isComplexDataType = obj= > (typeof obj === 'object' || typeof obj === 'function') && (obj ! = =null)

// Use WeekMap() to refer to its own keys as weak references. If there are no other references to the same object, the object will be garbage collected
// To solve the problem of circular reference, set up a hash table to store the copied object for cyclic detection, when the detection of the current object exists in the hash table, fetch the value and return
const deepClone = function (obj, hash = new WeakMap(a)) {
    // Check the hash table to prevent cyclic copying. Obj =>obj.loop= original obj if looped (object loop reference), the first obj will be found in weekMap
    if (hash.has(obj)) return hash.get(obj)

    // If the parameter is a reference type such as Date, RegExp, Set, Map, WeakMap, WeakSet, etc., a new instance will be generated directly
    let type = [Date.RegExp.Set.Map.WeakMap.WeakSet]
    if (type.includes(obj.constructor)) return new obj.constructor(obj)

    // Iterate over all attribute descriptors for the passed argument
    let allDesc = Object.getOwnPropertyDescriptor(obj)

    // Inherit the prototype
    let cloneObj = Object.create(Object.getPrototypeOf(obj), allDesc)

    // Get all Symbol type keys
    let symKeys = Object.getOwnPropertySymbols(obj)

    // Copy the property corresponding to the Symbol key
    if (symKeys.length > 0) {
        symKeys.forEach(x= > {
            cloneObj[x] = isComplexDataType(obj[x]) ? deepClone(obj[x], hash) : obj[x]
        })
    }

    // Hash table set values
    hash.set(obj, cloneObj)

    // reflect.ownkeys (obj) copies non-enumerable property and symbol types
    for (let key of Reflect.ownKeys(obj)) {
        // deepClone is recursively called if the value is a reference type and not a function
        cloneObj[key] = (isComplexDataType(obj[key]) && typeofobj[key] ! = ='function')? deepClone(obj[key], hash) : obj[key] }return cloneObj
}

let obj = {
    arr: [0.1.2.3.4.5.6]}let obj2 = deepClone(obj)
obj2.str = 'flten'
console.log('[ obj2 ] >', obj2)

console.log('-- -- -- -- -- -- -- -- -- -- -- -- --');

// Handle cyclic reference tests
let a = {
    name: 'lsz'.course: {
        vue: 'vue.js'.react: 'react.js'
    },
    a1: undefined.a2: null.a3: 123.a4: NaN
}
// Object loop reference
a.circleRef = a

let b = deepClone(a)
console.log('[ b ] >', b)
Copy the code
[ obj2 ] > {  
  arr: Array {
    '0': 0.'1': 1.'2': 2.'3': 3.'4': 4.'5': 5.'6': 6.length: 7 
  },
  str: 'flten'
}
------------- 
[ b ] > {     
  name: 'lsz'.course: { vue: 'vue.js'.react: 'react.js' },
  a1: undefined.a2: null.a3: 123.a4: NaN.circleRef: [Circular]
}
Copy the code