You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将嵌套的含不可枚举属性的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;
};

代码解释

  1. parseErrors函数:

    • 用Object.getOwnPropertyDescriptors获取Error的所有自有属性(包括stack、cause这些不可枚举的)
    • 创建新对象,把这些属性的值直接赋值,新对象的属性默认都是可枚举的
    • 完全保留了Error的原始堆栈、message等信息
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 13:05:15