简单版的深拷贝
function deepClone(obj) {
if(typeof obj !== 'object' || obj == null) return obj
let res
if(obj instanceof Array) res = []
else res = {}
for(const i in obj) {
if(obj.hasOwnProperty(i)){
res[i] = deepClone(obj[i])
}
}
return res
}
拓展版的深拷贝
具体方法:
识别是否为循环引用:函数添加一个map对象,该对象中存储所有使用使用过的对象,每次判断前先看是否为循环引用,是则直接返回对象
识别Map Set:使用instanceof来判断,但必须放在object之前。因为Map和Set对象instanceof Object都为真
过程:
依次判断循环引用、Map、Set、Array、Object
如有需要判断其他类型对象,可在循环引用后,object之前添加判断
function deepClone(obj, map = new WeakMap()) {
// 这里还可以添加其他类型的,比如date,视情况而定
if(typeof obj !== 'object' || obj == null) return obj
// 先判断是否为循环引用
const objFromMap = map.get(obj) // 拿到关联的值
if(objFromMap) return objFromMap //为真,说明是循环引用,则直接返回,不继续往下判断
let res = {} // 这里必须先赋值为空对象,如果是不在这里赋值,在下面判断是赋值则会出现值类型都为object情况
map.set(obj, target) // 将obj与target进行关联
if (obj instanceof Map) {
res = new Map() // 重新定义为map类型
// map的值和键都有可能为object。注意,对map使用forEach时,值在前,键在后
obj.forEach((v,k) => {
const v1 = deepClone(v, map)
const k1 = deepClone(k, map)
res.set(k1, v1)
})
}
if(obj instanceof Set) {
res = new Set()
// set的值有可能为object
obj.forEach((v) => {
const v1 = deepClone(v)
res.add(v1)
})
}
if (obj instanceof Array) {
res = obj.map(item => deepClone(item, map))
}
for(const key in obj) {
if (obj.hasOwnProperty(key)){
res[key] = deepClone(obj[key], map)
}
}
return res
}
输出结果如下,非常简单