修改嵌套层级很深对象的 key

实现一个函数,能够递归遍历深层嵌套对象,修改指定的 key 名称

问题

在实际开发中,我们经常需要处理后端返回的数据结构,有时需要将对象中的某些 key 进行重命名。当对象嵌套层级很深,且需要修改的 key 可能出现在任意层级时,就需要一个通用的解决方案来递归处理整个对象树。

例如:将对象中所有的 old_key 重命名为 newKey,无论它出现在哪一层。

解答

/**
 * 修改嵌套对象中的 key
 * @param {Object|Array} obj - 需要处理的对象或数组
 * @param {String} oldKey - 旧的 key 名称
 * @param {String} newKey - 新的 key 名称
 * @returns {Object|Array} 返回修改后的新对象
 */
function renameDeepKey(obj, oldKey, newKey) {
  // 处理 null 和 undefined
  if (obj === null || obj === undefined) {
    return obj;
  }

  // 处理数组
  if (Array.isArray(obj)) {
    return obj.map(item => renameDeepKey(item, oldKey, newKey));
  }

  // 处理非对象类型(基本类型)
  if (typeof obj !== 'object') {
    return obj;
  }

  // 处理对象
  const newObj = {};
  
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      // 判断当前 key 是否需要重命名
      const currentKey = key === oldKey ? newKey : key;
      const value = obj[key];
      
      // 递归处理值
      newObj[currentKey] = renameDeepKey(value, oldKey, newKey);
    }
  }
  
  return newObj;
}

/**
 * 批量修改多个 key(支持映射对象)
 * @param {Object|Array} obj - 需要处理的对象或数组
 * @param {Object} keyMap - key 映射关系,如 { oldKey1: 'newKey1', oldKey2: 'newKey2' }
 * @returns {Object|Array} 返回修改后的新对象
 */
function renameDeepKeys(obj, keyMap) {
  if (obj === null || obj === undefined) {
    return obj;
  }

  if (Array.isArray(obj)) {
    return obj.map(item => renameDeepKeys(item, keyMap));
  }

  if (typeof obj !== 'object') {
    return obj;
  }

  const newObj = {};
  
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      // 查找映射关系,如果存在则使用新 key,否则保持原 key
      const currentKey = keyMap[key] || key;
      const value = obj[key];
      
      newObj[currentKey] = renameDeepKeys(value, keyMap);
    }
  }
  
  return newObj;
}

使用示例

// 示例 1: 修改单个 key
const data1 = {
  user_name: 'Alice',
  user_info: {
    user_name: 'Bob',
    age: 25,
    address: {
      user_name: 'Charlie'
    }
  },
  list: [
    { user_name: 'David' },
    { user_name: 'Eve' }
  ]
};

const result1 = renameDeepKey(data1, 'user_name', 'userName');
console.log(result1);
/* 输出:
{
  userName: 'Alice',
  user_info: {
    userName: 'Bob',
    age: 25,
    address: {
      userName: 'Charlie'
    }
  },
  list: [
    { userName: 'David' },
    { userName: 'Eve' }
  ]
}
*/

// 示例 2: 批量修改多个 key
const data2 = {
  user_name: 'Alice',
  user_age: 30,
  user_info: {
    user_name: 'Bob',
    user_age: 25,
    contact_email: 'bob@example.com'
  }
};

const keyMap = {
  user_name: 'userName',
  user_age: 'userAge',
  contact_email: 'email'
};

const result2 = renameDeepKeys(data2, keyMap);
console.log(result2);
/* 输出:
{
  userName: 'Alice',
  userAge: 30,
  user_info: {
    userName: 'Bob',
    userAge: 25,
    email: 'bob@example.com'
  }
}
*/

// 示例 3: 处理复杂嵌套结构
const data3 = {
  old_key: 'value1',
  nested: {
    old_key: 'value2',
    deep: {
      old_key: 'value3',
      array: [
        { old_key: 'value4' },
        { old_key: 'value5', other: 'data' }
      ]
    }
  }
};

const result3 = renameDeepKey(data3, 'old_key', 'newKey');
console.log(JSON.stringify(result3, null, 2));

关键点

  • 递归遍历:使用递归方式遍历对象的所有层级,确保能处理任意深度的嵌套结构

  • 类型判断:需要区分处理数组、对象和基本类型,避免对非对象类型进行错误操作

  • 数组处理:使用 map 方法遍历数组,对每个元素递归调用函数

  • 不可变性:创建新对象而不是修改原对象,避免副作用,符合函数式编程思想

  • hasOwnProperty 检查:使用 hasOwnProperty 确保只处理对象自身的属性,不处理原型链上的属性

  • 扩展性:提供批量修改版本 renameDeepKeys,支持一次性修改多个 key,提高效率

  • 边界处理:正确处理 nullundefined 等特殊值,增强函数的健壮性