目录
在解决深拷贝的时候要用到ES6新增的weakMap,和map一样,都是采取键值对存储的机制,其中的weak是指描述JS垃圾回收中的弱映射,也就是在weakmap中存储的值,并不会引用计数。
WeakMap:
API
初始化:
const wm = new WeakMap()
weakmap中的键,也就是key:value中的key必须是Object类型或是继承自Object类型,否则会抛出TypeError,初始化是全有或者全无的操作,例如:
const wm = new WeakMap([["key","value"]])//TypeError: Iterator value key is not an entry object
const stringKey = new String("key");
console.log(typeof stringKey);//Object
const wm1 = new WeakMap([[stringKey,"value"]])//注意要有两个[[]]
console.log(wm1.get(stringKey));//value
get()/set()/has():
const stringKey = new String("key");
console.log(typeof stringKey);//Object
const wm1 = new WeakMap([[stringKey,"value"]])//注意要有两个[[]]
console.log(wm1.get(stringKey));//value
const stringKey2 = new String('key2')
wm1.set(stringKey2,'value2')
console.log(wm1.get(stringKey2));//value2
console.log(wm1.has(stringKey2));//查询键名,true
Weak:
Weak中的键处于弱引用,即引用计数不增加,但是键对应的值却不是弱引用,只要键存在,则值就存在,不会被当做垃圾回收。同时weakmap中的键值对因为在任何时候都可能会被销毁,所以不需要拥有迭代能力,也没有clear()方法来一次性的销毁。同时因为不可迭代,所以无法在不知道对象引用情况下从键去的值,所以即使访问到weakmap实例也无法知道其内容。
console.log(wm1);//WeakMap { <items unknown> }
判断是否发生了循环引用 :
let a={},b={}
a.b = b
b.a = a
function isCall(obj,hash = new WeakMap()){
if(obj == null || typeof obj !== 'object')return obj //若为基本数据类型、function、Date、正则,直接返回
if(obj instanceof RegExp)return//typeof RegExp也为 object
if(obj instanceof Date)return
//判断是否为循环引用
if(hash.get(obj)){
console.log("发生了循环引用");
return hash.get(obj)
}
//创建空的数组/对象
let newobj = obj.constructor()
hash.set(obj,newobj)
//循环遍历
for(let key in obj){
//如果当前为obj自有属性
if(obj.hasOwnProperty(key))isCall(obj[key],hash)
}
return
}
isCall(a)//发生了循环引用
深拷贝:
与以往的深拷贝由一些不同点:
1.利用WeakMap判断是否发生了循环引用
2.一般的深拷贝会对传进来的对象进行判断,看是对象还是数组:
const newData = Array.isArray(obj)?[]:{}
可以直接利用构造函数来new 一个空的数组或是对象
let cloneObj = new obj.constructor()
3.hasOwnProperty()判断自有属性
完整代码:
function DeepClone(obj,hash = new WeakMap()){
if(obj == null || typeof obj !== 'object')return obj //若为基本数据类型、function、Date、正则,直接返回
if(obj instanceof RegExp)return new RegExp(obj) //typeof RegExp也为 object
if(obj instanceof Date)return new Date(obj)//typeof Date也为 object
//判断是否为循环引用
if(hash.get(obj))return hash.get(obj)
//创建空的数组/对象
let cloneObj = new obj.constructor()
hash.set(obj,cloneObj)
//循环遍历
for(let key in obj){
//如果当前为obj自有属性
if(obj.hasOwnProperty(key)){
cloneObj[key] = DeepClone(obj[key],hash)
}
}
return cloneObj
}