js手写深拷贝

72 阅读1分钟

最近项目需要用到深拷贝,不想去单独安装一个库,就自己手写了。

支持基本数据,null,undefined,布尔,数字,字符串。支持Object类型的 Map,Set,Promise,正则,日期,函数,数组,Object 类型数据。另外也支持里面数据内有属性是引用的。

let _toString = Object.prototype.toString

function isPrimitive(val) {
    if (val === null) {
        return true
    }
    return !(typeof val === 'object' || typeof val === 'function')
}

function getRegExpFlags(re) {
    let flags = ''
    if (re.global) flags += 'g'
    if (re.ignoreCase) flags += 'i'
    if (re.multiline) flags += 'm'
    return flags;
}

function deepClone(obj) {
    if (isPrimitive(obj) || typeof obj == 'function') {
        return obj
    }

    let everyVal = []
    let result = undefined

    if (obj instanceof Map) {
        result = new Map()
    } else if (obj instanceof Set) {
        result = new Set()
    } else if (obj instanceof Promise) {
        result = new Promise(function (resolve, reject) {
            obj.then(function (value) {
                resolve(deepClone(value))
            }, function (err) {
                reject(deepClone(err))
            })
        })
    } else if (Array.isArray(obj)) {
        result = []
    } else if (_toString.call(obj) === '[object RegExp]') {
        result = new RegExp(obj.source, getRegExpFlags(obj))
        if (obj.lastIndex) result.lastIndex = obj.lastIndex
    } else if (_toString.call(obj) === '[object Date]') {
        result = new Date(obj.getTime())
    } else if (obj instanceof Error) {
        result = Object.create(obj)
    } else {
        let proto = Object.getPrototypeOf(obj)
        result = Object.create(proto)
    }

    let index = everyVal.indexOf(obj)
    if (index !== -1) {
        return everyVal[index]
    }
    everyVal.push(obj)

    for (let k in obj) {
        result[k] = deepClone(obj[k])
    }
    return result
}