JavaScript深度嵌套对象搜索父级属性丢失问题修复
深度嵌套对象关键词搜索实现方案
需求说明
需要在自研应用中实现对象搜索能力,支持对深度嵌套的Object执行关键词检索,返回结果需保持和输入对象完全一致的结构。
测试用示例数据如下:
const obj = { Cricket: { description: "", stadiums: { Australia: { Melbourne: { match: "IND VS ENG", }, Sydney: { match: "BAN VS PAK", }, }, India: { Wankhede: { match: "NZ VS AUS", }, Eden_Gardens: { match: "SA VS WI", }, }, }, }, Football: { description: "", stadiums: { UK: { Trafford: { match: "MU VS AR", }, Emirates: { name: "LIV VS MC", }, }, Spain: { Wanda: { match: "RM VS BOC", }, Santiago: { match: "BAR VS VIL", }, }, }, }, };
预期效果
- 搜索关键词
Cric时,返回结果:
{ Cricket: { description: '', stadiums: { Australia: [Object], India: [Object] } } }
- 搜索关键词
tiago(匹配Santiago字段)时,返回结果:
{ Football: { description: '', stadiums: { Spain: [Object] } } }
原有代码缺陷
原有递归逻辑仅处理了值为对象的属性,当深层子节点命中搜索条件时,命中路径上父节点的非对象同级属性(比如示例中的description字段)会被直接丢弃,无法保留。
原有代码如下:
const search = (obj, text) => { const searchRegex = RegExp(text, 'i'); return Object.keys(obj).reduce((acc, curr) => { if (searchRegex.test(curr) && typeof obj[curr] === 'object') { acc[curr] = obj[curr]; } else { if (typeof obj[curr] === 'object') { const result = search(obj[curr], text); if (Object.keys(result).length > 0) { acc[curr] = result; } } } return acc; }, {}); };
修复后实现
修复逻辑
- 新增命中标记:判断当前节点是否自身存在匹配的key,或存在命中搜索条件的子节点
- 若当前key直接匹配搜索词,直接保留该key对应的完整子树,无需向下递归,减少不必要计算
- 若当前节点被标记为命中,补全当前节点下所有非对象类型的原始属性,避免同级属性丢失
- 新增null值判断,避免
typeof null === 'object'导致的递归报错
修复后代码:
const search = (obj, text) => { const searchRegex = new RegExp(text, 'i'); const result = {}; let hasMatched = false; // 先遍历处理key匹配项、递归对象类型子节点 for (const key of Object.keys(obj)) { const value = obj[key]; // 当前key匹配,直接保留完整子节点 if (searchRegex.test(key)) { result[key] = value; hasMatched = true; continue; } // 递归处理对象类型子节点 if (typeof value === 'object' && value !== null) { const childResult = search(value, text); if (Object.keys(childResult).length > 0) { result[key] = childResult; hasMatched = true; } } } // 当前节点存在匹配时,补全所有非对象类型的同级属性 if (hasMatched) { for (const key of Object.keys(obj)) { if (key in result) continue; const value = obj[key]; if (typeof value !== 'object' || value === null) { result[key] = value; } } } return result; };
该实现可完全符合两个场景的预期输出,命中路径上的所有父节点属性都会被完整保留,非命中分支的节点会被正确过滤。
内容的提问来源于stack exchange,提问作者Frosted Cupcake
相关产品推荐
相关产品推荐

