Node.js 如何打印循环引用的对象(JSON 格式)?

JSON.stringify 遇到循环引用直接报错。解决方案:用 util.inspect 打印(自动处理循环引用),或给 JSON.stringify 传 replacer 函数剔除循环引用。本文给出三种写法。

最佳实践
Node.js 事件循环与异步任务示意

最简单:用 util.inspect(),天生支持循环引用。JSON.stringify 遇到循环引用会直接抛 TypeError: Converting circular structure to JSON。

方法一:util.inspect(推荐)

const util = require('util');

const obj = {
  prop1: 'value1',
  prop2: { prop3: 'value3' }
};
obj.circularRef = obj;   // 制造循环引用

console.log(util.inspect(obj, { depth: null }));
// 输出: { prop1: 'value1', prop2: { prop3: 'value3' }, circularRef: <ref *1> [Circular] }

depth: null 取消默认的嵌套层级限制(默认只展开 2 层),循环引用处显示 <ref *1> [Circular]。

其实直接 console.log(obj) 内部也走 util.inspect,同样能打印循环结构——只是层级深了会被折叠。

方法二:JSON.stringify + replacer

需要真正的 JSON 字符串(比如要写文件)时,用 replacer 函数剔除循环引用:

const seen = new WeakSet();
const json = JSON.stringify(obj, (key, value) => {
  if (typeof value === 'object' && value !== null) {
    if (seen.has(value)) return '[Circular]';  // 见过的对象替换为占位符
    seen.add(value);
  }
  return value;
}, 2);

console.log(json);

方法三:现成库

safe-stable-stringify、flatted 等库处理了更多边界(BigInt、Map、性能),项目里高频遇到循环引用(如打印 ORM 实体)时直接用库。

常见问题(FAQ)

Q:循环引用从哪来的?
常见于:ORM 实体互相关联(User.posts → Post.author → User)、DOM-like 树结构(parent/children)、Express 的 req/res 对象。

Q:util.inspect 的输出能再 JSON.parse 回来吗?
不能,它是给人看的调试格式,不是合法 JSON。要可序列化用方法二/三。

Q:为什么打印 express 的 req 会炸?
req 内部有大量循环引用(req.res.req...)。别整个打印,挑需要的字段(method、url、headers)输出。

参考资料

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台