
本文介绍如何将形如 `"0_tags.0.various.test-string"` 的键名自动解析并构建为深层嵌套对象结构,避免硬编码层级,支持任意深度的路径映射。
在处理配置驱动型数据(如 IoT 设备标签、JSON Schema 路径或表单字段映射)时,常需将扁平化的点号分隔键(例如 "root.child.grandchild")动态还原为对应的嵌套对象结构。若采用 if 判断逐层创建(如 obj[a][b][c] = value),不仅代码冗余、难以维护,更无法应对不确定的嵌套深度。
✅ 推荐方案:递归路径解析函数
核心思路是将每个键按 . 分割为路径数组,再通过递归或迭代方式逐级下钻创建中间对象,最终在叶子节点赋值:
function createNestedObject(obj, keys, value) {
const [head, ...tail] = keys;
if (tail.length === 0) {
// 到达末级:直接赋值
obj[head] = value;
} else {
// 中间层级:确保子对象存在,继续递归
if (!obj[head] || typeof obj[head] !== 'object') {
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));? 输出效果:自动合并同前缀路径,生成符合预期的嵌套结构——如 "0_tags.0.Various.X" 全部归入 result["0_tags"]["0"]["Various"] 下,且各子项保留原始 common/native 数据。
⚠️ 注意事项与增强建议
- 空值防护:递归中已加入 typeof obj[head] !== 'object' 判断,防止已有非对象值被意外覆盖;
-
性能考量:对超大规模数据(>10k 条),可改用迭代版避免调用栈过深:
function setByPath(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] || typeof current[key] !== 'object') { current[key] = {}; } current = current[key]; } current[keys.at(-1)] = value; } - 键名转义兼容性:若路径含特殊字符(如 .、[、]),需先对原始键做 URL 编码或使用 lodash.set() 等成熟工具;
- 重复键处理:当前逻辑以最后出现的值为准;如需合并冲突值(如数组聚合),应在叶子节点做自定义逻辑判断。
掌握该模式后,你不仅能精准还原题设中的多层设备标签结构,还可无缝扩展至动态表单生成、路由配置树、JSON Patch 路径解析等场景——真正实现“一法通百用”。










