json深拷贝无法处理循环引用,因其设计上拒绝引用关系,遇自引用或闭环引用直接抛typeerror;替代方案有structuredclone()、weakmap手写深拷贝或lodash clonedeep。

JSON 方法本身无法处理循环引用,直接报错,不是“怎么处理”,而是“根本不能处理”。JSON.stringify() 在遇到对象内部存在自引用或闭环引用时,会抛出 TypeError: Converting circular structure to JSON,整个流程中断,后续的 JSON.parse() 根本不会执行。
为什么 JSON 深拷贝对循环引用完全失效
JSON 是一种纯数据交换格式,不支持引用关系。它只认可可序列化的值:字符串、数字、布尔、null、数组、普通对象(键为字符串,值为可序列化类型)。以下情况都会导致失败:
- 对象属性指向自身:
obj.a = obj - 两个对象互相引用:
a.b = b; b.a = a - 深层嵌套形成闭环(如树节点 parent/children 循环)
常见误试及结果
有人尝试加 try-catch 或预检测,但都绕不开底层限制:
-
try { JSON.parse(JSON.stringify(obj)) } catch(e) { ... }→ 只能捕获错误,无法修复或跳过 - 手动遍历检测循环引用再剔除字段 → 破坏原始结构,已不是“拷贝”
- 用
replacer函数过滤掉疑似引用字段 → 无法可靠识别,且仍可能漏报或误删
真正可行的替代方案
若必须支持循环引用,应放弃 JSON 方法,改用以下任一方式:
-
structuredClone():浏览器和 Node.js(v18.13+)原生支持,自动处理循环引用、Date、Map、Set、ArrayBuffer 等,但不支持函数、undefined、Symbol 和正则标志(
flags会丢失) -
手写 deepClone + WeakMap:用
WeakMap缓存已遍历对象,递归中查表拦截重复访问,可完整保留函数、正则、原型链等,需自行适配各类内置类型 - Lodash cloneDeep:经长期验证的成熟实现,覆盖绝大多数边界场景,包括循环引用,但引入额外包体积
一句话总结
JSON 深拷贝与循环引用是互斥的——它不是“处理不了”,而是设计上就拒绝这种结构;需要循环引用支持,就得换用 structuredClone 或带 WeakMap 缓存的手写方案。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











