JavaScript 转换合并同结构JSON对象为指定嵌套结构方法
嵌套对象同路径值合并问题
需求说明
假设给定如下JSON对象:
{ "a": { "title": { "text": "text a" } }, "b": { "title": { "text": "text b" } } }
需要转换合并为如下目标结构:
{ "title": { "text": { "a": "text a", "b": "text b" } } }
第二个示例:给定3个结构完全一致的对象aObject、bObject、cObject:
let aObject = { "level1": { "level2": { "level3": "text a" } } } let bObject = { "level1": { "level2": { "level3": "text b" } } } let cObject = { "level1": { "level2": { "level3": "text c" } } }
需要合并为如下结构:
{ "level1": { "level2": { "level3": { "aObject": "text a", "bObject": "text b", "cObject": "text c" } } } }
这类操作没有通用的标准专业术语,核心逻辑是递归遍历所有源对象的嵌套路径,将相同路径下的叶子节点值,以源对象的键名为属性名收集到同一层对象中,实现复杂度低,属于常规的嵌套对象处理场景。
现有可运行实现
提问者已经完成了基础版本的实现,希望得到更简洁的写法,现有代码如下:
let object = { "a": { "title": { "text": "text a" } }, "b": { "title": { "text": "text b" } } } function reduce(node, object, result = {}) { for (let key in object) { if (typeof result[key] === 'undefined') { result[key] = {} } if (typeof object[key] === 'string') { result[key][node] = object[key] } else { reduce(node, object[key], result[key]) } } return result } let result = Object.entries(object).reduce((result, [key, value]) => { return reduce(key, value, result) }, {}) console.log(result)
精简实现方案
可以将递归逻辑和入口合并,减少冗余参数,同时兼容两个示例的使用场景:
const mergeNested = (...entries) => entries.reduce((res, [rootKey, obj]) => { const dive = (target, currentNode) => { Object.entries(currentNode).forEach(([key, val]) => { if (typeof val === 'object' && val !== null) { target[key] ??= {} dive(target[key], val) } else { target[key] ??= {} target[key][rootKey] = val } }) } dive(res, obj) return res }, {}) // 第一个示例调用方式 const demo1Obj = { "a": {"title": {"text": "text a"}}, "b": {"title": {"text": "text b"}} } console.log(mergeNested(...Object.entries(demo1Obj))) // 第二个示例调用方式 const aObject = {"level1": {"level2": {"level3": "text a"}}} const bObject = {"level1": {"level2": {"level3": "text b"}}} const cObject = {"level1": {"level2": {"level3": "text c"}}} console.log(mergeNested( ['aObject', aObject], ['bObject', bObject], ['cObject', cObject] ))
方案特点:
- 用
??=空值赋值运算符替代手动判断属性是否为undefined的冗余代码 - 递归遍历逻辑内聚,不需要额外传递临时结果对象作为参数
- 兼容任意数量、任意嵌套深度的源对象,只要所有源对象的非叶子节点路径完全一致即可正常合并
- 适配两种使用场景:第一种直接拆分源对象的键值对传入即可,第二种手动传入自定义键名和源对象的组合即可,不需要额外修改逻辑
- 增加了
val !== null的判断,避免null值被误判为对象进入递归导致报错
内容的提问来源于stack exchange,提问作者Muhammet Ilendemli
相关产品推荐
相关产品推荐

