深拷贝要注意存在循环引用的问题
先来看看例子:
function deepCopy(obj) { if(typeof obj !== 'object') return obj if(obj === null) return null if(obj.constructor === Date) return new Date(obj) if(obj.constructor === RegExp) return new RegExp(obj) const res = Array.isArray(obj) ? [] : {}; for (let key in obj) { if (typeof obj[key] === "object") { res[key] = deepCopy(obj[key]); } else { res[key] = obj[key]; } } return res; } var obj = { a: 1, b: 2, c: [1, 2, 3], d: { aa: 1, bb: 2 }, }; obj.e = obj; console.log("obj", obj); // 不会报错 const objCopy = deepCopy(obj); console.log(objCopy); //Uncaught RangeError: Maximum call stack size exceeded
从例子可以看到,当存在循环引用的时候,deepCopy 会报错,栈溢出。
循环应用问题解决
即:目标对象存在循环应用时报错处理大家都知道,对象的 key 是不能是对象的。
{{a:1}:2} // Uncaught SyntaxError: Unexpected token ':'
解决办法一
使用 weakmap 解决循环引用问题,我们可以额外开辟一个存储空间,来存储当前对象和拷贝对象的对应关系
这个存储空间,需要可以存储 key-value 形式的数据,且 key 可以是一个引用类型,我们可以选择 weakMap 这种数据结构:
- 检查 weakMap 中有无克隆过的对象。
- 有,直接返回
- 没有,将当前对象作为 key,克隆对象作为 value 进行存储
- 继续克隆
function deepClone(obj, hash = new WeakMap()) { if(typeof obj !== 'object') return obj if(obj === null) return null if(obj.constructor === Date) return new Date(obj) if(obj.constructor === RegExp) return new RegExp(obj) if(hash.has(obj)) return hash.get(obj) let target = Array.isArray(obj) ? [] : {} hash.set(obj, target) Object.keys(obj).forEach(item => { if (isObj(obj[item])) { target[item] = deepClone(obj[item], hash) } else { target[item] = obj[item] } }) return target } // test var a = { a: 123, b: isObj, c: [1,2,3,4,5, { a: 123}], d: undefined } a.e = a var b = deepClone(a) console.log(`b`, b)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论