引言
一般使用 JSON.parse(JSON.stringify(obj))可以实现对象的深拷贝,但是,对于属性值为undefined,Date类的实例和RegExp的实例通过这种方式不能实现深拷贝,于是就要手写一个方法实现深拷贝,深拷贝的实质就是,把引用类型的值在堆内存中再开辟一块空间,内容跟被拷贝者一样只是引用他们的地址值不同
代码
//如果遇到obj.xxx=obj,就会出现递归的死循环,就要把这种对象放到一个WeakMap中
//如果再需要直接从中获取,避免递归的死循环
function deepClone(obj,hash=new WeakMap()){
//处理undefined和null,Date和RegExp类实例,返回值
if(obj==null)return obj
if(obj instanceof Date)return new Date(obj)
if(obj instanceof RegExp)return new RegExp(obj)
//如果不是数组或对象就返回原来的值
if(typeof obj!=="object")return obj
if(hash.has(obj))return return hash.get(obj)
let newObj=new obj.constructor()
hash.set(obj,newObj)
for(let key in obj){
if(obj.hasOwnProperty(key)){
newObj[key]=deepClone(obj[key],hash)
}
}
}
解析使用WeakMap
当要拷贝的对象中obj有属性xxx对应的属性值还是obj的时候obj={xxx:obj}
深度拷贝这个对象,当到xxx属性时又会把obj深度拷贝,这样就会形成一个递归死循
环为了避免这个情况,就要把拷贝过的对象的拷贝前的对象作为map的key,拷贝后的对象作为值存到map中,这样每当进来的是一个对象要循环它进行拷贝之前,先判断它是否已经拷贝过,如果是直接把拷贝后的值返回,否则,创建一个新对象,遍历原来的对象进行拷贝,还要把新对象,就对象放到map中
总结
就是要保证之前拷贝过的对象只拷贝一次,并把拷贝前的值作为WeakMap的key,而拷贝后的值作为WeakMap的值,每次都要从WeakMap中使用has确定是否含有该对象的拷贝后的对象,如果有直接返回,不用再拷贝对象了,如果没有把他放到map中,然后遍历拷贝新值
为啥要用WeakMap
正常的map如果key是一个对象,在没有变量引用它的时候由于他是Map的key浏览器不会清楚它,如果WeakMap浏览器会清楚一个没有引用的对象,即便它是WeakMap映射的 key