对象深克隆和浅克隆

134 阅读2分钟

JavaScript基础类型

  • JavaScript原始类型:number、string、boolean、null、undefined、symbol(ES6)、bigint(ES10)
  • JavaScript引用类型:Object(function、array、object)

1.浅克隆

定义:对象只会被克隆最外部的一层,至于更深层的对象,则依然是通过引用指向同一块内存。

//浅克隆函数
function shallowClone(o){
    const obj = {}'
    for(let i in o){
        obj[i] = o[i];
    }
    return obj;
}
//被克隆对象
const oldObj = {
    a:1,
    b:['a','b','c'],
    c:{h:{i:2}}
};
const newObj = shallowClone(oldObj);
console.log(newObj.c.h,oldObj.c.h); //{i:2} {i:2}
console.log(oldObj.c.h === newObj.c.h); //true

可以从oleObj.c.h和newObj.c.h相等可以看出,他们依然指向的是同一段内存,这就造成了如果对newObj.c.h修改的话,也会影响oleObj.c.h

newObj.c.h.i = 'change';
console.log(newObj.c.h,oldObj.c.h); //{i:'change'} {i:'change'}

2.对象深度克隆实现

定义:开辟一块新的空间,完整的复制一份,包括复杂数据类型,拷贝的这个对象和原对象无任何关系,修改什么都互不影响。

  • JSON.parse方法:JSON对象parse方法可以将JSON字符串反序列化成JS对象,stringify方法可以将JS对象序列化成JSON字符串,这两个方法结合起来就能产生一个便捷的深克隆
const newObj = JSON.parse(JSON.stringify(oldObj));

console.log(newObj.c.h === oldObj.c.h); //false
newObj.c.h.i = 'change';
console.log(newObj.c.h,oldObj.c.h); //{i:'change'} {i:2}

缺点:

  1. 他无法实现对函数、RegExp等特殊对象的克隆
  2. 会抛弃对象的constructor,所有的构造函数会指向Object
  3. 对象有循环引用,会报错
  • 构造一个深克隆函数(递归实现)
//ES5实现方式
function deepClone(obj){
    var newObj = obj instanceof Array?[]:{}
    for(var item in obj){
        var temple = typeof obj[item] == 'object'?deepClone(obj[item]):obj[item];
        newObj[item] = temple;
    }
    return newObj;
}

//完整解决方案
function deepClone(obj){
    if(obj === null) return null;
    if(obj instanceof Date) return newDate(obj); //日期对象
    if(obj instanceof RegExp) return RegExp(obj); //正则表达式
    if(typeof obj === 'Function') return new function(obj){}; //函数
    if(typeof obj !== 'object'){
        //非复杂类型,直接返回 也是结束递归的条件
        return obj
    }
    //[].__proto__.constructor = Array()
    //{}.__proto__.constructor = Object()
    //因此处理数组情况是,可以巧用这个办法来new新对象
    var newObj = new obj.__proto__constructor;
    for(var key in obj){
        newObj[key] = deepClone(obj[key])
    }
    return newObj;
}

知识点补充:

  • typeof和instanceof区别?

    typeof可以判断出基本数据类型(除了null的数据类型为object的bug),还可以正确判断出某个对象是否为function,其余的Date,Array等无法判断

    instanceof相反,可以准确判断出复杂数据类型,但是无法判断简单数据类型