实现深拷贝

深拷贝相对浅拷贝而言,如果遇到属性值为引用类型的时候,它新建一个引用类型并将对应的值复制给它,因此对象获得的一个新的引用类型而不是一个原有类型的引用。深拷贝对于一些对象可以使用 JSON 的两个函数来实现,但是由于 JSON 的对象格式比 js 的对象格式更加严格,所以如果属性值里边出现函数或者 Symbol 类型的值时,会转换失败

(1)JSON.stringify()

  • JSON.parse(JSON.stringify(obj))是目前比较常用的深拷贝方法之一,它的原理就是利用JSON.stringify 将js对象序列化(JSON字符串),再使用JSON.parse来反序列化(还原)js对象。
  • 这个方法可以简单粗暴的实现深拷贝,但是还存在问题,拷贝的对象中如果有函数,undefined,symbol当使用过JSON.stringify()进行处理之后,都会消失。

(2)函数库lodash的_.cloneDeep方法

该函数库也有提供_.cloneDeep用来做 Deep Copy

 

(3)手写实现深拷贝函数

步骤:

  1. 先判断map中是否已经存在(已经拷贝过了),存在则返回,防止循环引用(进入死循环会导致栈内存溢出)
  2. 判断(instanceof)当前类型是不是Object,如果不是直接返回target
  3. 如果是,再判断其是不是数组,函数,正则(RegExp),日期,或者是普通对象,对应的创建不同类型的数据
  1. 数组:newobj=[]
  2. 函数:newobj=function(){return target.call(this,...arguments)}
  3. 正则:newobj=new RegExp(target.source,target.flags)
  4. 日期:newobj=new Date(target)
  5. 普通对象:newobj={}

4,加入map进行标记 map.set(target,newobj)

5,遍历target的属性,如果是自身的属性,则递归赋值给新对象 newobj[key]=dd(target[key],map)

6,返回新对象newobj

function dd(target,map=new WeakMap()){
    //循环
    if(map.get(target)){
        return map.get(target)
    }
    if(target instanceof Object){
        let newobj;
        if(target instanceof Array){
            newobj=[]
        }else if(target instanceof Function){
            newobj=function(){
                return target.call(this,...arguments)
            }
        }else if(target instanceof RegExp){
            newobj=new RegExp(target.source,target.flags)
        }else if(target instanceof Date){
            newobj=new Date(target)
        }else{
            newobj={}
        }
        //标记
        map.set(target,newobj)
        for(let key in target){
            if(target.hasOwnProperty(key)){
                newobj[key]=dd(target[key],map)
            }
        }
        return newobj
    }else{
        return target
    }

}
let obj={
    a:function(){
        console.log('a')
    },
    b:{
        c:'d'
    },
    d:[1,2,3,4]
}
let r=dd(obj)
console.log(obj.a())
console.log(r)

关于weakMap:

WeakMap的作用:

WeakMap 对象是一组键/值对的集合,其中的键是弱引用的。其键必须是对象,而值可以是任意的。

什么是弱引用呢?

在计算机程序设计中,弱引用与强引用相对,是指不能确保其引用的对象不会被垃圾回收器回收的引用。 一个对象若只被弱引用所引用,则被认为是不可访问(或弱可访问)的,并因此可能在任何时刻被回收。

 我们默认创建一个对象:const obj = {},就默认创建了一个强引用的对象,我们只有手动将obj = null,它才会被垃圾回收机制进行回收,如果是弱引用对象,垃圾回收机制会自动帮我们回收。

举个例子:

如果我们使用Map的话,那么对象间是存在强引用关系的:

let obj = { name : 'ConardLi'}
const target = new Map();
target.set(obj,'code秘密花园');
obj = null;
复制代码

虽然我们手动将obj,进行释放,然是target依然对obj存在强引用关系,所以这部分内存依然无法被释放。

再来看WeakMap

let obj = { name : 'ConardLi'}
const target = new WeakMap();
target.set(obj,'code秘密花园');
obj = null;
复制代码

如果是WeakMap的话,targetobj存在的就是弱引用关系,当下一次垃圾回收机制执行时,这块内存就会被释放掉。

设想一下,如果我们要拷贝的对象非常庞大时,使用Map会对内存造成非常大的额外消耗,而且我们需要手动清除Map的属性才能释放这块内存,而WeakMap会帮我们巧妙化解这个问题。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值