深拷贝要注意存在循环引用的问题

发布于 2022-05-10 20:34:50 字数 1879 浏览 898 评论 0

先来看看例子:

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 这种数据结构:

  1. 检查 weakMap 中有无克隆过的对象。
  2. 有,直接返回
  3. 没有,将当前对象作为 key,克隆对象作为 value 进行存储
  4. 继续克隆
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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

拒绝两难

暂无简介

0 文章
0 评论
25 人气
更多

推荐作者

daid

文章 0 评论 0

我心依旧

文章 0 评论 0

晒暮凉

文章 0 评论 0

微信用户

文章 0 评论 0

DS

文章 0 评论 0

〆凄凉。

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文