如何将嵌套的含不可枚举属性的Error对象转为可枚举?
解决方案:克隆含嵌套Error的对象并转换Error属性可枚举性
原代码的问题
你写的递归函数存在两个核心问题:
- 处理普通对象时,遍历属性的循环里直接
return,导致只处理第一个属性就终止,完全丢失了原对象的结构 - 没有创建新的对象来承载克隆后的结构,无法保留原对象的层级关系
正确实现思路
要满足需求,我们需要:
- 递归遍历对象的每一层属性
- 对Error实例,提取其所有自有属性(包括不可枚举的),并转移到一个新的可枚举对象中,保留原始堆栈、message、cause等信息
- 对普通对象/数组,创建新的容器,递归处理每个子属性后赋值,不改动原对象的属性可枚举性
- 排除
null(因为typeof null === 'object',需要单独处理)
完整代码实现
// 处理Error对象:提取所有自有属性转为可枚举 const parseErrors = (err: Error): Record<string, any> => { // 获取Error的所有自有属性(包括不可枚举的) const allProps = Object.getOwnPropertyDescriptors(err); const errorObj: Record<string, any> = {}; // 将所有属性转为可枚举并赋值到新对象 for (const [key, descriptor] of Object.entries(allProps)) { errorObj[key] = descriptor.value; } return errorObj; }; // 递归克隆并处理对象 const parseObjects = (exception: any): any => { // 处理null的情况 if (exception === null) return null; // 遇到Error时,转换为可枚举属性的对象 if (exception instanceof Error) { return parseErrors(exception); } // 处理数组:创建新数组,递归处理每个元素 if (Array.isArray(exception)) { return exception.map(item => parseObjects(item)); } // 处理普通对象:创建新对象,递归处理每个属性 if (typeof exception === 'object') { const newObj: Record<string, any> = {}; // 获取对象的所有自有属性(不管是否可枚举) const properties = Object.getOwnPropertyNames(exception); for (const property of properties) { newObj[property] = parseObjects(exception[property]); } return newObj; } // 基本类型直接返回 return exception; };
代码解释
parseErrors函数:
- 用
Object.getOwnPropertyDescriptors获取Error的所有自有属性(包括stack、cause这些不可枚举的) - 创建新对象,把这些属性的值直接赋值,新对象的属性默认都是可枚举的
- 完全保留了Error的原始堆栈、message等信息
- 用
parseObjects函数:
- 先处理
null,避免误判为对象 - 遇到Error直接调用
parseErrors转换 - 数组单独处理:创建新数组,递归处理每个元素
- 普通对象:创建新对象,遍历所有自有属性,递归处理每个属性后赋值到新对象,保留原结构
- 基本类型(字符串、数字等)直接返回
- 先处理
测试示例
let one = { myErr: new Error('测试错误') }; let two = { prop: { nested: new Error('嵌套错误') } }; const clonedOne = parseObjects(one); const clonedTwo = parseObjects(two); // 验证Error属性可枚举 console.log(Object.keys(clonedOne.myErr)); // 会输出 ["stack", "message", "cause", ...] console.log(clonedTwo.prop.nested.stack); // 能正常访问原始堆栈
内容的提问来源于stack exchange,提问作者myol
相关产品推荐
相关产品推荐

