json深拷贝遇bigint报typeerror,解决关键是拦截序列化:用replacer转bigint为字符串,或现代环境用structuredclone原生支持;也可预清洗字段,但需避免污染原型、吞错误等陷阱。

JSON深拷贝遇到 BigInt 就报错,不是“小坑”,而是明确中断执行的 TypeError:Do not know how to serialize a BigInt。它不跳过、不忽略、不静默丢数据,而是直接崩掉整个流程。解决的关键,是不让 BigInt 进入 JSON.stringify 的默认序列化路径。
用 replacer 函数拦截并转成字符串
这是兼容性最好、逻辑最干净的通用解法。replacer 在遍历每个值时做类型判断,只对 BigInt 做处理,其余原样透传:
- 遇到 typeof value === 'bigint',返回 value.toString(),精度零丢失
- 嵌套对象、数组、多层结构自动生效,无需递归手写
- 配合 JSON.parse 可完成一次“伪深拷贝”,结果里 BigInt 变成字符串,但结构完整
示例:
const copy = JSON.parse(JSON.stringify(obj, (k, v) => typeof v === 'bigint' ? v.toString() : v));
改用 structuredClone(现代环境首选)
Node.js 18.13+ 或 Chrome 115+ 起,structuredClone() 已原生支持 BigInt、Map、Set、Date、RegExp、循环引用等——它不是“绕过”问题,而是真正理解并复制这些类型:
- 一行调用:const copy = structuredClone(obj)
- 拷贝后 123n 还是 123n,类型不变,语义不损
- 不污染原型、不需预处理、不改变原始数据结构
注意:Safari 和旧版 Node.js 尚未支持,上线前建议加运行时检测。
提前清洗再走标准流程
如果你清楚哪些字段固定是 BigInt(比如 Prisma 查询结果里的 id、count、balance),可以先轻量清洗,再用任意深拷贝方法:
- 遍历对象,对已知 key 名(如 id、userId、total)统一 toString()
- 或全局扫描所有 bigint 值:if (typeof val === 'bigint') obj[key] = val.toString()
- 清洗后可放心用 JSON.parse(JSON.stringify())、lodash.cloneDeep 等工具
优点是逻辑外显、调试方便;缺点是需要维护字段约定,不适合结构高度动态的场景。
别踩这些“省事”陷阱
有些做法看似快捷,实则埋雷:
- 往 BigInt.prototype 加 toJSON:TS 报错、污染全局、可能与其他库冲突
- try-catch 吞掉错误:错误没了,但数据可能已截断或丢失,后续计算出错更难定位
- 用 + 或 parseInt 强转:超出 Number.MAX_SAFE_INTEGER 就失真,比如 9007199254740992n → 9007199254740992(表面一样,实际已非精确值)
真正安全的深拷贝,不是让错误消失,而是让 BigInt 从一开始就不触发错误。











