json.stringify 无法处理循环引用会抛出错误,解决方案包括:① json-stringify-safe(轻量、标记为[circular ~]);② flatted(支持双向序列化/反序列化);③ cycle.js(已归档、不推荐);④ weakmap 自定义 replacer(零依赖但不可逆)。

JavaScript 中 JSON.stringify 无法处理循环引用,会直接抛出 TypeError: Converting circular structure to JSON。要解决这个问题,通常需要借助第三方库或自定义 replacer 函数。以下是几个成熟、轻量、广泛使用的第三方方案。
json-stringify-safe(最轻量的兼容方案)
这是一个极简但可靠的库,专为解决循环引用而生,不修改原对象,只在序列化时跳过重复引用。
- 安装:
npm install json-stringify-safe - 用法简单,API 与原生
JSON.stringify一致:
const obj = { a: 1 };
obj.self = obj;
console.log(stringify(obj)); // {"a":1,"self":"[Circular ~]"}
它会把循环引用标记为 [Circular ~],保留结构可读性,适合日志、调试等非传输场景。
flatted(支持反序列化的双向方案)
如果不仅需要序列化,还要求后续能还原成原始结构(含循环),flatted 是目前最推荐的方案。它用扁平化方式编码引用关系,支持完整 round-trip。
- 安装:
npm install flatted - 序列化 + 反序列化示例:
const obj = { name: 'Alice' };
obj.friend = obj;
const str = flatted.stringify(obj); // '{"name":"Alice","friend":{"_":"0"}}'
const restored = flatted.parse(str); // 恢复循环引用
console.log(restored === restored.friend); // true
它生成的字符串是标准 JSON 子集,兼容性好,体积小(仅 ~2KB),适用于需要保真传输的场景(如跨 worker、持久化缓存)。
cycle.js(老牌经典,但已不再维护)
由 Douglas Crockford 开发,曾是早期主流方案,通过临时添加 $ref 字段标记引用路径。
- 安装:
npm install cycle - 使用需显式调用
cycle.decycle()和cycle.retrocycle()
缺点是输出不是纯 JSON(含额外元字段),且项目已归档,不建议新项目采用。仅作了解,避免踩坑。
自定义 replacer + WeakMap(零依赖方案)
若想不引入外部依赖,可用 WeakMap 记录已访问对象,跳过重复项或替换为占位符:
const seen = new WeakMap();
return JSON.stringify(obj, (key, value) => {
if (typeof value === 'object' && value !== null) {
if (seen.has(value)) return '[Circular]';
seen.set(value, true);
}
return value;
});
}
注意:该方法不可逆,适合只读展示;若需还原,必须搭配更复杂的引用映射逻辑,此时不如直接用 flatted。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











