
本文介绍一种通用、不可变的 JavaScript 递归处理方法,用于遍历任意深度的对象或数组,自动将形如 { en: "xxx" } 的多语言字段提取为字符串值,适用于国际化配置、CMS 数据清洗等场景。
本文介绍一种通用、不可变的 javascript 递归处理方法,用于遍历任意深度的对象或数组,自动将形如 { en: "xxx" } 的多语言字段提取为字符串值,适用于国际化配置、cms 数据清洗等场景。
在实际开发中(尤其是处理国际化内容或 CMS 返回的多语言结构时),我们常遇到类似这样的嵌套数据:
{
"name": { "en": "Contact Champion", "fr": "Contacter le Champion" },
"description": { "en": "Initial talk...", "fr": "Premier échange..." }
}而业务逻辑往往只需要当前语言(如 "en")的字符串值,而非整个语言对象。此时,手动逐层取值既繁琐又易出错,尤其当数据结构深度不固定、且包含数组与对象混合嵌套时。
下面提供一个类型安全、纯函数式、深度递归的解决方案:
✅ 核心函数:liftTargetKey
该函数接收两个参数:
-
value: 待处理的数据(可为任意类型:原始值、数组、普通对象) -
targetKey: 要“提升”的键名(如"en")
它遵循三原则递归处理:
- 原始值(string/number/boolean/null/undefined) → 直接返回;
- 数组 → 对每个元素递归调用自身;
-
普通对象 → 遍历所有键值对,若当前值是对象且存在
targetKey(如val?.en),则取其值;否则继续递归处理该值。
const liftTargetKey = (value: any, targetKey: string): any => {
// 情况1:原始值(非对象,包括 null)
if (Object(value) !== value) return value;
// 情况2:数组 → 递归映射每个元素
if (Array.isArray(value)) {
return value.map((item) => liftTargetKey(item, targetKey));
}
// 情况3:普通对象 → 递归处理每个属性,并尝试提取 targetKey
return Object.fromEntries(
Object.entries(value).map(([key, val]) => [
key,
// 优先尝试 val[targetKey](如 val.en),否则递归处理 val
val != null && typeof val === 'object' && targetKey in val
? val[targetKey]
: liftTargetKey(val, targetKey)
])
);
};? 使用示例
假设你有一组任务配置数据(含多语言字段):
const inputArray = [{
"id": "e8546367-d643-4da0-80dc-0980c9935ded",
"offsetSeconds": 86400,
"tasks": {
"id": "contactChampionInitialTalk",
"icon": "0",
"skills": ["skillCommunityManager"],
"name": { "en": "Contact Champion" },
"description": { "en": "Initial talk, agreement on the theme..." }
}
}];
// 提取所有层级中的 "en" 字段值
const result = liftTargetKey(inputArray, "en");
console.log(JSON.stringify(result, null, 2));输出结果完全符合预期——name 和 description 已从 { en: "xxx" } 扁平化为 "xxx" 字符串,且深层嵌套、数组、混合结构均被正确处理。
⚠️ 注意事项与最佳实践
- 不可变性保障:函数全程不修改原始数据,返回全新对象/数组,适合 React/Vue 等响应式框架及 Redux 等状态管理场景;
-
健壮性设计:显式检查
val != null && typeof val === 'object' && targetKey in val,避免null或undefined访问报错; -
扩展性强:只需更换
targetKey参数(如"zh"、"ja"),即可切换语言提取逻辑; -
TypeScript 友好:可进一步添加泛型约束(如
<t></t>)和类型守卫,提升类型安全性; - 性能提示:对于超大规模数据(万级节点),可考虑加入缓存或迭代替代递归以规避栈溢出,但日常业务场景中递归完全足够。
掌握这一模式后,你不仅能解决多语言字段扁平化问题,还可轻松适配其他类似需求——例如统一提取 id、uri、label 等嵌套标识字段,真正实现「一次编写,多处复用」。

















