当前位置: 首页 > Web前端 > JavaScript

实现深拷贝

时间:2023-03-27 11:34:30 JavaScript

深拷贝浅拷贝:就是拷贝引用(地址)。即复制后,原变量和新变量指向同一个东西,对彼此的操作会互相影响。深拷贝:在堆中重新分配内存,地址不同,但值相同。复制的对象与原对象完全隔离,互不影响。深拷贝和浅拷贝的主要区别在于:是拷贝引用(地址)还是拷贝实例。不使用第三方库的实现比如现在我们要对下面的对象做一个深拷贝,不使用第三方库如何实现。constsource={field1:1,field2:undefined,field3:'hello',field4:null,field4:{child:'小明',child2:{child2:'阿红'}},fieldArray:[1,2,3,4]}obj->JsonString->newObjJSON.parse(JSON.stringify(source));手动实现原始数据类型,直接复制引用类型,新建一个对象,将每个属性的深拷贝赋值给新对象。分两个方向,实现了第一个简单的深拷贝。1.1functionclone2(target){if(typeoftarget=='object'&&target!=null){让cloneTarget=Array.isArray(target)?[]:{}for(letkeyintarget){cloneTarget[key]=clone2(target[key])}returncloneTarget}else{returntarget}}如果这种实现是指自己,source.XXX=sourcestack溢出。1.2如何优化?开辟一个新的存储空间,用于存储当前对象与复制对象的对应关系。当当前对象需要复制时,先到存储空间中查找该对象是否被复制过。functionclone3(target,targetMap=newMap()){if(typeoftarget=='object'&&target!=null){让cloneTarget=Array.isArray(target)?[]:{}if(targetMap.get(target)){returntarget}targetMap.set(target,cloneTarget)for(letkeyintarget){cloneTarget[key]=clone3(target[key],targetMap)}返回cloneTarget}else{returntarget}}Map是强引用,如果引用级别很高,垃圾回收机制不会主动帮我们回收,可能会出现性能问题。那你可以考虑把Map换成WeakMap,WeakMap是ES6提供的原生数据结构。只要删除对该对象的其他引用,垃圾回收机制就会释放该对象占用的内存,从而避免内存泄漏。functionclone4(target,targetMap=newWeakMap()){if(typeoftarget=='object'&&target!=null){让cloneTarget=Array.isArray(target)?[]:{}if(targetMap.get(target)){returntarget}targetMap.set(target,cloneTarget)for(letkeyintarget){cloneTarget[key]=clone4(target[key],targetMap)}返回cloneTarget}else{returntarget}}1.3众所周知,forin的速度比for循环和while要慢,所以修改循环。functionclone5(target,targetMap=newWeakMap()){if(typeoftarget=='object'&&target!=null){让cloneTarget=Array.isArray(target)?[]:{}if(targetMap.get(target)){returntarget}targetMap.set(target,cloneTarget)letkeys=Array.isArray(target)?null:Object.keys(target)letlength=(keys||target).lengthletindex=-1while(++index{if(keys){key=value}cloneTarget[key]=clone6(target[key],targetMap)})returncloneTarget}else{returntarget}}这只是一个简单的版本,适用于大部分业务数据的深拷贝,并没有考虑函数的类型等,详见原文,或者看lodash的源码