JSON.stringify 不支持循环引用,会抛出 TypeError;需用 replacer 函数配合 WeakMap 跳过、预处理删除循环字段(如 parent)、或用 flatted/cycle 等库实现序列化与还原。

JSON.stringify 本身不支持循环引用,遇到时会直接抛出 TypeError: Converting circular structure to JSON 错误。要解决这个问题,不能靠原生方法自动处理,必须主动干预——要么提前移除/替换循环引用,要么用自定义 replacer 函数跳过或标记它。
用 replacer 函数跳过循环引用
replacer 参数可以是数组(过滤键)或函数(逐个处理键值对)。函数形式能捕获当前遍历路径,配合 WeakMap 记录已访问对象,就能识别并跳过重复引用:
- 创建一个 WeakMap 存储“对象 → 序列号”映射,每次进入新对象就检查是否已存在
- 如果已存在,返回
undefined(JSON.stringify 会忽略该属性)或自定义标记如"[Circular]" - 注意:WeakMap 只接受对象作键,且不影响垃圾回收,适合临时追踪
预处理数据,切断循环引用
更可控的方式是在调用 stringify 前清理数据结构。比如后端返回的树形结构带 parent 指针,前端通常不需要序列化 parent:
- 递归遍历对象,删除已知的循环字段(如
parent、self、root) - 用深拷贝 + 过滤组合:先 structuredClone(现代环境)或 JSON.parse(JSON.stringify()) 粗略克隆,再手动删掉可疑字段
- 适用于结构固定、循环字段明确的场景,简单直接
用第三方库简化处理
像 flatted 或 cycle 这类库专门解决循环序列化问题:
立即学习“Java免费学习笔记(深入)”;
-
flatted.stringify(obj)会把循环转成带索引的引用格式(如{"$ref":"1"}),解析时也能还原 -
cycle提供decycle和retrocycle,把循环转为扁平描述,适合跨环境传输 - 适合需要完整保留结构、后续还要反序列化的场景
调试时快速定位循环位置
报错信息一般不指明哪一层出问题。可临时加个简易检测函数辅助排查:
- 写一个递归扫描器,用 Set 记录访问过的对象引用,遇到重复就 throw 并打印当前路径
- 在开发环境 console.log 前先跑一遍检测,比等 stringify 报错再查更快
- 例如:
if (isCircular(obj)) console.warn("Found circular reference in", obj)


















