深拷贝

68 阅读2分钟
一、JSON.parse(JSON.stringify))
 const obj = {
    a:1,
    b:['e','f','g'],
    c:{h:20},
    // JSON不能克隆方法
    d:function(){}
}
console.log(obj) // {"a": 1,"b": ["e","f","g"],"c": {"h": 20},"d": function()}
// 循环引用
obj.b.push(obj.c)
obj.c.j = obj.b
console.log(deepClone1(obj)) // {"a": 1,"b": ["e","f","g"],"c": {"h": 20}}
function deepClone1(target){
    let str = JSON.parse(JSON.stringify(target))
    return str
}
缺点:
1. JSON不能克隆方法
2.循环引用报错

image.png

二、递归拷贝
function deepClone1(target) {
    // 判断数据类型
    if (typeof(target) === 'object' && target !== null) {
        // 创建一个容器
        const result = Array.isArray(target) ? [] : {}
        // 遍历对象
        for (let key in target) {
            if (target.hasOwnProperty(key)) {
                // 拷贝
                result[key] = deepClone1(target[key])
            }
        }
        return result
    } else {
        return target
    }
}
  const obj = {
    a:1,
    b:['e','f','g'],
    c:{h:20},
    // JSON不能克隆方法
    d:function(){}
}
obj.b.push(obj.c)
obj.c.j = obj.b
/*
    报错  Uncaught RangeError: Maximum call stack size exceeded
*/
console.log(obj) // {"a": 1,"b": ["e","f","g"],"c": {"h": 20},"d": function()}
const result = deepClone1(obj)
result.c.h = 2300
console.log(result) // {"a": 1,"b": ["e","f","g"],"c": {"h": 2300},"d": function()}
三、递归拷贝(解决循环引用报错)
function deepClone1(target,map=new Map()) {
    // 判断数据类型
    if (typeof(target) === 'object' && target !== null) {
        // 克隆数据之前 进行判断 数据之前是否客隆过
        let cache = map.get(target)
        if(cache) return cache
        // 创建一个容器
        const result = Array.isArray(target) ? [] : {}
        // 将新的结果存入到容器中
        map.set(target,result)
        // 遍历对象
        for (let key in target) {
            if (target.hasOwnProperty(key)) {
                // 拷贝
                result[key] = deepClone1(target[key],map)
            }
        }
        return result
    } else {
        return target
    }
}
const obj = {
    a:1,
    b:['e','f','g'],
    c:{h:20},
    // JSON不能克隆方法
    d:function(){}
}
obj.b.push(obj.c)
obj.c.j = obj.b
console.log(obj) // {"a": 1,"b": ["e","f","g"],"c": {"h": 20},"d": function()}
const result = deepClone1(obj)
result.c.h = 2300
console.log(result) // {"a": 1,"b": ["e","f","g"],"c": {"h": 2300},"d": function()}
四、优化for in(解决循环引用报错)
function deepClone1(target,map=new Map()) {
    // 判断数据类型
    if (typeof(target) === 'object' && target !== null) {
        // 克隆数据之前 进行判断 数据之前是否客隆过
        let cache = map.get(target)
        if(cache) return cache
        // 创建一个容器
        let isArray = Array.isArray(target)
        const result = isArray ? [] : {}
        // 将新的结果存入到容器中
        map.set(target,result)
        // 遍历对象
        if(isArray){
            target.forEach((item,index) =>{result[index] = deepClone1(item,map)})
        }else{
            Object.keys(target).forEach(key =>{result[key] = deepClone1(target[key],map)})
        }
        return result
    } else {
        return target
    }
}
const obj = {
    a:1,
    b:['e','f','g'],
    c:{h:20},
    // JSON不能克隆方法
    d:function(){}
    }
    obj.b.push(obj.c)
    obj.c.j = obj.b
    console.log(obj) // {"a": 1,"b": ["e","f","g"],"c": {"h": 20},"d": function()}
    const result = deepClone1(obj)
    // result.c.h = 2300
    console.log(result) // {"a": 1,"b": ["e","f","g"],"c": {"h": 2300},"d": function()}