深入深拷贝

JS中如何实现深拷贝

1.实现深拷贝的方法

  • JSON.stringify()、JSON.parse()方法组合

let people = {
    name:"ivanadmin",
    age:"18",
}
JSON.stringify(people)
let people2 = JSON.parse(JSON.stringify(people))

不妨思考一个问题如果拷贝的对象有环那么这种方法是否可行呢?答案是不成功的
不仅如此,JSON.stringify()方法会将函数、undefined、symbol、正则表达式、Date对象等转化为字符串,而JSON.parse()方法会将字符串转化为对象,因此,如果对象中包含函数、undefined、正则表达式、Date对象等,那么使用JSON.stringify()和JSON.parse()组合的方法是无法实现深拷贝的。

  • 递归

接下来手撕一下递归的深拷贝方法:
【常见的方法】

function deepClone(obj) {
    if(typeof obj !== 'object' || obj === null){
        return obj;
    }
    //创建一个空对象或空数组来存储克隆后的对象
    let result = Array.isArray(obj) ? [] : {};
    for(let key in obj){
        result[key] = deepClone(obj[key]);
    }
    return result;
}



let obj = {
    a: 1,
    b: {
        c: 2,
        d: [3, 4]
    }
};

let clonedObj = deepClone(obj);
console.log(clonedObj); // 输出: { a: 1, b: { c: 2, d: [ 3, 4 ] } }
console.log(obj === clonedObj); // 输出: false,说明是深拷贝

【优化方法】主要考虑到循环引用的问题,使用一个WeakMap来记录已经访问过的对象,如果再次访问到已经访问过的对象,则直接返回该对象,而不是重新创建一个新的对象。
为什么使用WeakMap而不是Map?因为WeakMap中的键是弱引用的,当键不再被引用时,键会被垃圾回收机制回收,而Map中的键是强引用的,即使键不再被引用,也不会被垃圾回收机制回收。

let people = {
    name:"ivanadmin",
    age:"18",
}
people.selfReference  = people;

// 那么如何实现深拷贝一个带环的对象呢?
// 这里采用递归+WeakMap实现
// console.log(people);
function deepClone(obj,map=new WeakMap()){
    if(typeof obj !=="object" || obj === null){
        return obj;
    }
    //当这个对象被引用过,直接返回引用避免死循环
    if(map.has(obj)){
        return map.get(obj);
    }
    //接下来就是逐一判断obj类型了
    let result = Array.isArray(obj)?[]:{};//创建一个空对象或者空数组
    //如果走到了这一步那么就说明这个对象没有被引用过
    map.set(obj,result);
    for(let key in obj){
        obj.hasOwnProperty(key) && (result[key] = deepClone(obj[key],map));
    }
    return result;

}
let dog = deepClone(people)
console.log(`拷贝成功${dog}`);
//看下他们是否会指向同一个引用
console.log(dog === people);
//以及他的循环是否被拷贝
console.log(dog.selfReference === people);//false
console.log(dog.selfReference === dog);//true

总结:

递归遍历的深拷贝方法,首先判断对象是否为null或者不是对象类型,如果是则直接返回该对象,否则创建一个空对象或者空数组来存储克隆后的对象。然后遍历对象的属性,如果属性是自身的属性,则递归调用deepClone方法,并将克隆后的属性赋值给新的对象。最后返回新的对象。如果考虑循环引用的问题,可以使用WeakMap来记录已经访问过的对象,如果再次访问到已经访问过的对象,则直接返回该对象,而不是重新创建一个新的对象。避免死循环!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值