deepClone实现

87 阅读1分钟

针对每一种数据类型作特殊处理:

  1. 简单数据类型、null、undefined:返回本身即可
  2. Array Map、Set:对每一项元素作递归处理,最后返回
  3. Date:返回new Date(+o)+o相当于 o.getTime() 返回的是时间戳
  4. RegExp:返回new RegExp(o)
  5. Object:对每一个非继承属性作递归处理,最后返回
function deepClone(o, visited = new WeakMap()) {
    // 简单数据类型、null、undefined
    if (typeof o != 'object' || o == null) return o

    if (visited.has(o)) return visited.get(o) // 处理循环引用的情况

    // Array:五种数组判断方法,总有一款适合你
    if (
        Array.isArray(o) ||
        o instanceof Array ||
        o.__proto__ === Array.prototype ||
        o.__proto__.constructor === Array ||
        Object.prototype.toString.call(o).slice(8, -1) === 'Array'
    ) {
        let ret = []
        visited.set(o, ret)
        for (let i = 0; i < arr.length; i++) ret.push(deepClone(arr[i], visited))
        return ret
    }
    // Date
    if (o instanceof Date) return new Date(+o)

    // RegExp
    if (o instanceof RegExp) return new RegExp(o)

    // Map
    if (o instanceof Map) {
        let ret = new Map()
        visited.set(o, ret)
        for (let [key, val] of o) ret.set(key, deepClone(val, visited))
        return ret
    }

    // Set
    if (o instanceof Set) {
        let ret = new Set()
        visited.set(o, ret)
        for (let val of Set) ret.add(deepClone(val, visited))
    }

    // Object
    let ret = {}
    visited.set(o, ret)
    for (let key in o) {
        if (!o.hasOwnProperty(key)) continue // 跳过原型属性
        ret[key] = deepClone(o[key])
    }
    return ret
}

考虑到会有循环引用的情况如: let b = { a }; let a = { b },对于对象类型属性加一个weakMap来记录是否访问过即visited.set(o, ret),若已访问过直接return visited.get(o)