javascript 默认深拷贝方法无法正确克隆error对象,因其name、message、stack等关键属性不可枚举或为getter;需手动提取属性并用原构造函数重建实例,兼顾子类与自定义字段。

JavaScript 中默认的深拷贝方法(如 JSON.parse(JSON.stringify()) 或多数通用 clone 工具)无法正确克隆 Error 对象——它们会丢失 name、message、stack 等关键属性,甚至变成空对象或 null。要可靠克隆 Error,必须手动提取并重建其核心属性。
为什么 Error 不能被 JSON 序列化
Error 实例是普通对象,但它的 message 和 stack 属于不可枚举属性(尤其 stack 通常为 accessor 属性),且 name 在某些引擎中也不在 JSON.stringify 的遍历路径中。调用 JSON.stringify(new Error('test')) 得到的是 {},导致信息完全丢失。
手动构造新 Error 实例保留关键字段
最稳妥的方式是读取原 Error 的 name、message、stack(如果可读),然后用这些值创建新实例:
-
优先使用
error.name和error.message:这两个是自有可枚举属性,稳定存在 -
谨慎处理
error.stack:它是 getter 属性,部分环境(如某些打包器或严格模式)可能不可访问;建议用Object.getOwnPropertyDescriptor(error, 'stack')?.get?.call(error)安全读取 -
避免直接复制原型链或 Symbol 属性:Error 子类(如
SyntaxError)需用对应构造函数新建,而非统一用Error构造
支持子类和自定义属性的克隆逻辑
若需兼容 TypeError、SyntaxError 或带额外属性(如 code、cause)的错误,应:
- 检查
error.constructor是否为内置 Error 类型,若是则用相同构造函数实例化 - 遍历
Object.getOwnPropertyNames(error)获取所有自有属性(包括code、errno等 Node.js 常见扩展字段) - 对
cause(ES2022+)递归克隆,避免浅引用
实用的轻量克隆函数示例
以下函数可嵌入现有深拷贝流程中,专门处理 Error 类型:
function cloneError(err) {
if (!(err instanceof Error)) return err;
const Cls = err.constructor === Error ? Error : err.constructor;
const props = Object.getOwnPropertyNames(err);
const copy = new Cls(err.message);
for (const key of props) {
if (key !== 'message') {
copy[key] = err[key];
}
}
// 尝试复制 stack(仅当可读时)
const stackDesc = Object.getOwnPropertyDescriptor(err, 'stack');
if (stackDesc && stackDesc.get) {
try {
const stack = stackDesc.get.call(err);
if (stack) copy.stack = stack;
} catch {}
}
return copy;
}Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











