首页 > 其他分享 >深拷贝里的循环引用如何解决?

深拷贝里的循环引用如何解决?

时间:2024-12-12 09:59:38浏览次数:5  
标签:obj JSON 循环 引用 拷贝 copy

在前端 JavaScript 中,深拷贝遇到循环引用会导致栈溢出错误。解决这个问题的方法主要有以下几种:

1. 使用 WeakMap/WeakSet 追踪已拷贝对象:

这是最推荐的处理循环引用的方法。WeakMapWeakSet 不会阻止垃圾回收,所以即使它们持有对象的引用,对象仍然可以被回收。

function deepClone(obj, cache = new WeakMap()) {
  if (obj === null || typeof obj !== "object") {
    return obj;
  }

  if (cache.has(obj)) {
    return cache.get(obj); // 返回已拷贝的对象
  }

  let copy;
  if (Array.isArray(obj)) {
    copy = [];
  } else if (obj instanceof Date) {
    copy = new Date(obj);
  } else if (obj instanceof RegExp) {
    copy = new RegExp(obj);
  } else {
    copy = {};
  }

  cache.set(obj, copy); // 将原始对象和拷贝对象添加到 WeakMap

  for (const key in obj) {
    if (Object.hasOwnProperty.call(obj, key)) {
      copy[key] = deepClone(obj[key], cache); // 递归拷贝属性值
    }
  }

  return copy;
}

let original = {
  a: 1,
  b: {
    c: 2,
  },
};

original.b.d = original; // 创建循环引用

let cloned = deepClone(original);

console.log(cloned); // 深拷贝后的对象,没有栈溢出错误
console.log(cloned.b.d === cloned); // true,保持了循环引用关系

2. 使用 JSON.stringify 和 JSON.parse (有局限性):

这种方法简单快捷,但有几个重要的局限性:

  • 无法拷贝函数、Date、RegExp 等非 JSON 安全的对象。 这些对象会被转换为 null 或其他基本类型。
  • 无法处理循环引用。 遇到循环引用会抛出错误。 如果你的数据结构确定没有循环引用,或者可以接受丢失循环引用部分的数据,那么可以使用这种方法。
function simpleDeepClone(obj) {
  try {
      return JSON.parse(JSON.stringify(obj));
  } catch (error) {
      console.error("Error cloning object:", error);
      return null; // 或其他默认值
  }
}

3. 使用 lodash 的 _.cloneDeep() 方法:

Lodash 是一个流行的 JavaScript 工具库,提供了 _.cloneDeep() 方法,可以高效地进行深拷贝,并且能够处理循环引用。

const _ = require('lodash');

let original = { /* ... */ }; // 你的对象
let cloned = _.cloneDeep(original);

选择哪种方法?

  • 对于需要处理循环引用,并且需要保留所有数据类型(包括函数、Date、RegExp 等)的情况,推荐使用 WeakMap/WeakSet 方法
  • 对于简单的对象,并且不包含循环引用和特殊数据类型,可以使用 JSON 方法。 这也是性能最高的方法。
  • 对于需要处理各种复杂情况,并且希望使用成熟的库,可以使用 lodash 的 _.cloneDeep() 方法

总而言之,理解不同方法的优缺点,并根据实际情况选择合适的方法至关重要。 避免在不了解数据结构的情况下盲目使用 JSON.stringify/parse 方法,因为它可能会导致数据丢失或错误。 使用 WeakMap/WeakSet 方法可以更安全、更完整地进行深拷贝。

标签:obj,JSON,循环,引用,拷贝,copy
From: https://www.cnblogs.com/ai888/p/18601647

相关文章

  • 使用js按贝格尔编排算法生成单循环对阵表
    functionbergerAlgorithm(teams){if(!Array.isArray(teams)){thrownewError("Teamsmustbeanarray.");}constnumTeams=teams.length;if(numTeams<2){return[];//Nomatchespossiblewithlessthan2teams}/......
  • C++学习笔记 循环结构
    学习编程语言语法是次要的,思维是主要的。如何把头脑中的想法变成简洁的代码,至关重要。——闫学灿学习循环语句只需要抓住一点——代码执行顺序!一、while循环可以简单理解为循环版的if语句。if语句是判断一次,如果条件成立,则执行后面的语句;while是每次判断,如果条件成立,则执行循......
  • C语言之三种循环高级
    (1.)无限循环定义循环永远停不下来(注意点:无限循环因为永远停不下来,所以下面不能再写其他的代码了)(2.)跳转控制语句定义在循环的过程当中,跳到其他语句上执行break不能单独书写,只能写在switch,或者是循环中,表示结束,跳出的意思题目:在1-100之间,找第一个既能被3,又能被5整除的数......
  • 零拷贝技术
    概念零拷贝是一种优化技术,通过减少数据在不同内存区域之间的复制操作,从而提高数据传输效率和降低系统开销。零拷贝并不是没有拷贝数据,而是减少用户态/内核态的切换次数以及CPU拷贝的次数。传统IO流程CPU从用户态切换到内核态,DMA控制器将磁盘数据拷贝到内核缓冲区。CPU......
  • 【Azure Developer】使用cmd脚本循环执行curl请求
    问题描述在测试ApplicationInsights的每日上限(DailyCap)功能,想通过最简单的curl脚本来循环发送请求,验证日志摄入量大道设置的300MB(0.03GB)后,是否可以通过调大DailyCap限制值马上恢复数据的摄入! 问题解答一个简单的CMD脚本示例,它会循环执行 curl 命令:@echooff......
  • 【分布式系统】一文搞懂分布式服务发布和引用(Dubbo 案例解读)
    在分布式系统和微服务架构中,系统的能力来自服务与服务之间的交互和集成。为了实现这些过程,就需要服务提供者对外暴露可以访问的入口,而服务消费者就基于这些入口对服务提供者发起远程调用。我们来举一个例子,如果我们想要发布一个DemoService,那么可以使用这样的代码。DemoService......
  • 头歌第四章-之循环结构-练习2-学习-Java循环while之求非负数之和
    任务描述本关任务:使用Scanner对象接收一组数据,每组数据包含4个整数,其中有正有负,比如:2233-2232。请使用while循环求出每组数据的非负数之和(每组数据之间用空格分开,而组与组之间用换行符分开)。相关知识当我们想要对同样的操作执行多次,就需要使用到循环结构,在Java中......
  • 12.10 CW 模拟赛 T3. 循环
    算法很容易想到枚举短边断环之后\(\mathcal{O}(P)\)的求答案那么这个算法还有前途吗?可以发现,对于每次枚举断边,断\((i,i+1)\)和\((i-1,i)\)这两条边,变化量并不大,严格来说,均摊复杂度\(\mathcal{O}(P)\)具体实现上怎么处理呢?将断第\(x\)条边作为横......
  • 循环神经网络(RNN)原理及实现
    一、引言在深度学习领域,循环神经网络(RecurrentNeuralNetwork,RNN)是一类具有独特结构和强大功能的神经网络模型。与传统的前馈神经网络不同,RNN能够处理序列数据,如时间序列数据、文本数据等,这使得它在自然语言处理、语音识别、时间序列预测等众多领域都取得了广泛的应用和显著......
  • [C++11] 右值引用和移动语义
    目录左值引用和右值引用左值引用与右值引用比较​编辑右值引用使用场景和意义左值引用的使用场景:右值引用和移动语义移动拷贝移动赋值右值引用引用左值及其一些更深入的使用场景分析完美转发完美转发维持值自身属性完美转发的使用场景左值引用和右值引用什么......