json.stringify遇循环引用会报错,需提前切断或替换引用路径:可用replacer函数配合weakset标记已访问对象并返回"[circular]";或用structuredclone先深拷贝;也可自定义序列化器添加引用id;开发时可用findcircular定位循环路径。

JSON.stringify 遇到循环引用会直接报错:TypeError: Converting circular structure to JSON。这是因为 JSON 格式本身不支持对象间相互引用或自引用,而 JavaScript 对象可以任意嵌套、共享引用。解决的关键不是“绕过错误”,而是**提前切断或替换循环引用路径**。
用 replacer 函数跳过循环引用属性
replacer 参数可以是函数,它在序列化每个键值对前被调用,返回值决定是否保留该属性。利用一个 Set 记录已访问的对象,遇到重复引用就返回 undefined(该属性会被忽略):
const seen = new WeakSet();
const safeStringify = (obj) => {
return JSON.stringify(obj, (key, value) => {
if (typeof value === "object" && value !== null) {
if (seen.has(value)) return "[Circular]";
seen.add(value);
return value;
}
return value;
});
};
注意:WeakSet 更安全(避免内存泄漏),且必须在每次调用前重置 seen,否则跨调用会误判。实际使用时建议封装成闭包或每次新建:
- 每次调用都新建
new WeakSet() - 返回
"[Circular]"字符串比undefined更易调试(否则字段直接消失) - 只拦截 object 类型,避免影响原始值(number/string/boolean 等)
用结构克隆先解构再序列化
如果目标是“保留数据可读性”而非严格等价,可以用 structuredClone(现代浏览器/Node.js 17+)先深拷贝并断开引用,再 stringify:
try {
const cloned = structuredClone(obj);
const json = JSON.stringify(cloned);
} catch (e) {
// structuredClone 也会抛错(比如含 function、undefined、Symbol)
}
但它不解决所有情况——Map、Set、Date、RegExp 等仍需额外处理。更适合已知数据结构较干净的场景。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
自定义序列化器 + 标记引用关系
若需完整保留引用信息(比如调试、持久化还原),可实现带引用 ID 的序列化格式:
- 遍历对象树,给每个唯一对象分配 id(如递增数字或 Symbol)
- 遇到已见过的对象,不展开,而是写入
{"$ref": "id123"} - 最终输出包含
$defs或顶层$objects映射表
这类逻辑较重,一般用现成库更稳妥,比如 serialize-javascript(支持函数)、jsan(专为循环引用设计,输出可逆 JSON)。
开发阶段快速排查循环引用
临时加个检查函数,帮助定位哪两个对象连成了环:
function findCircular(obj, path = "", visited = new WeakMap()) {
if (typeof obj === "object" && obj !== null) {
if (visited.has(obj)) {
console.warn(`Circular reference at ${path} → ${visited.get(obj)}`);
return;
}
visited.set(obj, path);
for (const key in obj) {
findCircular(obj[key], `${path}.${key}`, visited);
}
}
}
调用 findCircular(myObj) 可打印出首个发现的循环路径,方便修复源头数据构造逻辑。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










