Lirx-Xin / LirxdeBlog

blog记录
0 stars 0 forks source link

对象深拷贝 #12

Open Lirx-Xin opened 3 years ago

Lirx-Xin commented 3 years ago

深拷贝

在实现深拷贝前,先实现一个判断Object的方法:

const isobject = (val) => typeof val === 'object' && val !== null;

先简单实现一个深拷贝:

function deepClone(souce){
    // 判断是不是对象,不是则直接返回
    if(!isobject(souce)){
        return souce;
    }
    var target = Array.isArray(souce) ? []:{}
    for(let i in souce){
        if(Object.prototype.hasOwnProperty.call(souce,i)){
            let val = souce[i]
            target[i] = isobject(val) ? deepClone(val) : val
        }
    }
    return target;
}

此时这个拷贝方法不能处理循环引用的情况,增加weakMap;

function deepClone(souce, Map = new WeakMap()){
    // 判断是不是对象,不是则直接返回
    if(!isobject(souce)){
        return souce;
    }
    // map中已存有该引用对象则直接取值
    if(Map.has(souce))return Map.get(souce);
    var target = Array.isArray(souce) ? []:{}
    // 将需要克隆的对象作为key,克隆生成的对象做value存储
    Map.set(souce,target)
    for(let i in souce){
        if(Object.prototype.hasOwnProperty.call(souce,i)){
            let val = souce[i]
            target[i] = isobject(val) ? deepClone(val , Map) : val
        }
    }
    return target;
}

拷贝symbol属性:

function deepClone(souce, Map = new WeakMap()){
    // 判断是不是对象,不是则直接返回
    if(!isobject(souce)){
        return souce;
    }
    // map中已存有该引用对象则直接取值
    if(Map.has(souce))return Map.get(souce);
    var target = Array.isArray(souce) ? []:{}
    // 将需要克隆的对象作为key,克隆生成的对象做value存储
    Map.set(souce,target)

    // 查看对象有没有symbol属性,有则克隆;
    const symbolkey = Object.getOwnPropertySymbols(souce)
    if(symbolkey.length){
        symbolkey.forEach(key => {
            let val = souce[key]
            target[key] = isobject(val) ? deepClone(val,Map) : val
        })
    }

    for(let i in souce){
        if(Object.prototype.hasOwnProperty.call(souce,i)){
            let val = souce[i]
            target[i] = isobject(val) ? deepClone(val,Map) : val
        }
    }
    return target;
}

克隆日期与正则类型

function deepClone(souce, Map = new WeakMap()){
    // 判断是不是对象,不是则直接返回
    if(!isobject(souce)){
        return souce;
    }
    if(Object.prototype.String.call(souce).slice(8,-1) === 'Date'){
        return new Date(souce)
    }
    if(Object.prototype.String.call(souce).slice(8,-1) === 'RegExp'){
        return new RegExp(souce)
    }
    // map中已存有该引用对象则直接取值
    if(Map.has(souce))return Map.get(souce);
    var target = Array.isArray(souce) ? []:{}
    // 将需要克隆的对象作为key,克隆生成的对象做value存储
    Map.set(souce,target)

    // 查看对象有没有symbol属性,有则克隆;
    const symbolkey = Object.getOwnPropertySymbols(souce)
    if(symbolkey.length){
        symbolkey.forEach(key => {
            let val = souce[key]
            target[key] = isobject(val) ? deepClone(val,Map) : val
        })
    }

    for(let i in souce){
        if(Object.prototype.hasOwnProperty.call(souce,i)){
            let val = souce[i]
            target[i] = isobject(val) ? deepClone(val,Map) : val
        }
    }
    return target;
}