
本文介绍一种通用、可扩展的方法,将形如 `”a.b.c”` 的键名自动解析为多层嵌套对象结构,并将对应值精准插入最深层,彻底避免硬编码层级判断。
在处理配置化数据(如 iot 设备标签、jsON Schema 路径映射或动态表单字段)时,常需将扁平化的点号分隔键(如 “0_tags.0.Various.Test-String”)还原为树状嵌套对象。原始代码仅支持固定两层(item[0] 和 item[1]),无法应对任意深度的路径,导致可维护性差且易出错。
解决的核心思路是:将路径字符串拆分为键数组,再通过递归或迭代方式逐层“钻取”并创建缺失节点,最终在叶子位置赋值。以下提供两种生产就绪的实现方案:
✅ 方案一:递归实现(清晰易懂)
function createNestedObject(obj, keys, value) { const [head, ...tail] = keys; // es6 解构,兼容现代环境 if (tail.length === 0) { obj[head] = value; } else { obj[head] = obj[head] || {}; createNestedObject(obj[head], tail, value); } } // 使用示例 const tagobject = { "0_tags.0": { common: {}, native: { topic: "Stromerfassung_251/Zähler0-Leistung" } }, "0_tags.0.Various": { common: {}, native: { topic: "Stromerfassung_251/Zähler0-Leistung" } }, "0_tags.0.Various.Stromerfassung_251/Zähler0-Leistung": { common: {}, native: { topic: "Stromerfassung_251/Zähler0-Leistung" } }, "0_tags.0.Various.Test-String": { common: {}, native: { topic: "Stromerfassung_251/Zähler0-Leistung" } }, "0_tags.0.Various.battery_charge": { common: {}, native: { topic: "Stromerfassung_251/Zähler0-Leistung" } } }; const result = {}; for (const key in tagObject) { createNestedObject(result, key.split('.'), tagObject[key]); } console.log(json.stringify(result, null, 2));
✅ 方案二:迭代实现(无栈溢出风险,推荐用于超深路径)
function setNestedProperty(obj, path, value) { const keys = path.split('.'); let current = obj; for (let i = 0; i < keys.length - 1; i++) { const key = keys[i]; if (current[key] === undefined || typeof current[key] !== 'object') { current[key] = {}; } current = current[key]; } current[keys[keys.length - 1]] = value; } // 批量应用 const result2 = {}; Object.entries(tagObject).forEach(([key, value]) => { setNestedProperty(result2, key, value); });
⚠️ 注意事项与最佳实践
- 键名合法性:若路径含特殊字符(如 . / [),需提前转义或使用 JSONPath 等专用库;
- 性能考量:对海量键(>10k),迭代版比递归版更稳定(避免 V8 栈限制);
- 空值防御:示例中使用 obj[head] = obj[head] || {} 替代 undefined 判断,更简洁鲁棒;
- 不可变更新:如需函数式编程风格,可封装为返回新对象的纯函数(配合 structuredClone 或 Lodash set);
- 类型安全:typescript 用户可定义泛型约束,确保 keys 为 string[],value 类型与目标结构一致。
该方法已广泛应用于 node.js 配置加载器、前端状态归一化(如 Redux Toolkit 的 createEntityAdapter 路径映射)及低代码平台元数据解析场景——一次编写,永久适配任意嵌套深度。