javascript中深拷贝error对象需特殊处理,因它含不可枚举属性(stack/message/name)且依赖原型链;json序列化丢失类型,structuredclone不复制自定义不可枚举属性,手写递归易漏关键字段。

JavaScript 中直接深拷贝 Error 对象不能靠通用方法“一招鲜”,因为 Error 是特殊内置对象:它有不可枚举属性(如 stack、message、name),原型链关键,且多数深拷贝方案会丢失其行为或结构。
为什么常见深拷贝会失败
• JSON.parse(JSON.stringify(err)):stack 可能被序列化为字符串,但 message 和 name 保留;err instanceof Error 返回 false,不再是 Error 实例。
• structuredClone(err):在支持环境中(Chrome 98+、Node.js 18.15+)可成功拷贝,保留 name、message、stack,且拷贝后仍是 Error 实例 ✅;但若 Error 含自定义属性(如 err.code = 'VALIDATION_FAILED'),这些**不可枚举属性默认不被复制**。
• 手写递归拷贝:若未显式处理 Error 类型,会把它当作普通对象遍历,漏掉 stack 或破坏原型,导致新对象无法被 catch 正确识别。
安全可靠的拷贝方式
推荐按场景选择:
-
只关心错误信息和类型(最常用):用
new Error(err.message)+ 手动赋值关键属性
✓ 保留instanceof Error
✓ 可继承子类(如class ValidationError extends Error)
✓ 示例:const copy = new err.constructor(err.message); copy.name = err.name; copy.stack = err.stack; if ('code' in err) copy.code = err.code; -
需完整保留所有自有可枚举 + 不可枚举属性:用
Object.getOwnPropertyDescriptors+Object.defineProperties
✓ 复制message、name、stack等不可枚举字段
✓ 保持原型链(Object.setPrototypeOf(copy, Object.getPrototypeOf(err)))
✓ 注意:跨 iframe 的 Error 可能无法完全还原 -
现代环境且无需函数/Symbol:优先用
structuredClone(err)
✓ 浏览器和较新 Node.js 已稳定支持
✓ 自动处理循环引用、Date、RegExp等,也兼容Error
✗ 不复制自定义不可枚举属性(如通过Object.defineProperty添加的)
避坑提醒
• 不要用 Object.assign({}, err) 或展开运算符 —— 它们只拷贝可枚举属性,stack 直接消失。
• err.toString() 或 err.stack 字符串化后重建,会丢失原始错误类型和堆栈上下文,调试困难。
• 若 Error 来自第三方库(如 AxiosError、ZodError),应查阅其文档是否有 .toJSON() 或 .clone() 方法,比通用拷贝更准确。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











