深拷贝:拷贝出来的对象与原对象毫无关系,不会拷贝引用,会进行深层次的拷贝
一、JSON序列化
const jsonString = JSON.stringify(obj)
const obj1 = JSON.parse(jsonString)
缺点:
- 对象中函数、undefined不会被处理,默认移除
- Symbol作为key或value都不会被处理,默认移除
- 如果存在对象的循环引用则会报错
- 对象中NaN、infinity会被转成null
- new Date日期会被自动转为字符串
- 正则reg、Map、Set会被转成空对象{}
二、自己实现深拷贝
解决循环引用造成的问题:
- 循环引用也就是 obj.info = obj
- 在深拷贝时,会造成栈溢出的情况,也就是不断地递归创建新的对象
- 那么怎么解决呢?
- 其实在第一次进入循环的时候,已经创建过一次拷贝对象了
- 那么直接返回原来生成的拷贝对象就可以了,没必要再创建一次
- 在深拷贝时,其实就是 newObj.info = newObj 将newObj作为info的值就可以了
- 用WeakMap去存放oldObj和newObj ```javascript function isObject(value) { const valueType = typeof value return value !== null && (valueType === ‘object’ || valueType === ‘function’) }
function deepClone(originValue, map = new WeakMap()) { // 利用map作为变量使得每次拿到的都是同一个map
// 判断set类型(浅拷贝) if (originValue instanceof Set) { return new Set([…originValue]) }
// 判断map类型(浅拷贝) if (originValue instanceof Map) { return new Map([…originValue]) }
// value为Symbol类型 if (typeof originValue === ‘symbol’) { return Symbol(originValue.description) }
// 判断function类型 if (typeof originValue === ‘function’) { return originValue }
// 判断object类型 if (!isObject(originValue)) { return originValue }
// 判断是否是之前已经拷贝过的对象 if (map.has(originValue)) { return map.get(originValue) }
const newObject = Array.isArray(originValue) ? [] : {} // 将原对象与拷贝对象形成映射 map.set(originValue, newObject) for (const key in originValue) { newObject[key] = deepClone(originValue[key], map) }
// Symbol作为key时进行特殊处理 const symbolKeys = Object.getOwnPropertySymbols(originValue) for (const sKey of symbolKeys) { newObject[sKey] = deepClone(originValue[sKey], map) }
return newObject } ```