json.stringify 遇到循环引用会主动抛错而非栈溢出,属安全熔断;真正解决需弃用 json 方法,改用 structuredclone()、weakmap 递归或 lodash clonedeep 等支持循环引用的深拷贝方案。

JSON 方法本身无法规避自引用导致的堆栈溢出——它根本不会规避,而是直接报错中断。
JSON.stringify 遇到自引用会立即失败
当对象存在循环引用(例如 obj.a = obj 或间接闭环),JSON.stringify() 在遍历过程中检测到重复引用,会立刻抛出:TypeError: Converting circular structure to JSON
这不是堆栈溢出(stack overflow),而是主动拒绝序列化,属于“安全熔断”,目的就是防止无限递归和内存失控。
试图用 try-catch + fallback 并不能“规避”问题
有人尝试这样写:
function safeJsonClone(obj) {
try {
return JSON.parse(JSON.stringify(obj));
} catch (e) {
// 降级处理……但此时已失败,没副本可用
return deepCopyWithMap(obj); // 必须另起一套逻辑
}
}
这只能避免程序崩溃,但不是对 JSON 方法本身的改进。一旦进到 catch,说明 JSON 路径彻底失效,必须切换为其他深拷贝方案。
真正能处理自引用的替代方案
要安全复制含自引用的对象,需放弃 JSON 方法,改用以下任一方式:
-
structuredClone()(推荐):现代浏览器和 Node.js(v17.0+)原生支持,自动识别并正确处理循环引用,保留 Date、Map、Set、RegExp 等类型,一行代码即可:
const clone = structuredClone(original); -
WeakMap + 递归函数:手动记录已拷贝对象,遇到重复引用时复用已有结果,避免递归深入:
function deepCopy(obj, map = new WeakMap()) { ... } - Lodash _.cloneDeep():经长期验证的成熟实现,内部已妥善处理循环引用与各类边界类型,适合需要兼容性或复杂数据结构的项目。
为什么不能“修复”JSON 方法来支持自引用
JSON 格式标准本身不支持引用语法(如 YAML 的 &id / *id),也没有循环结构的合法表示。ECMAScript 的 JSON.stringify 严格遵循该标准,因此技术上无法在不破坏规范的前提下支持自引用序列化。强行绕过只会导致不可移植、不可预测的结果。











