嵌套JSON中查找指定键值对,有无更优非库实现方案?
问题:深层嵌套JSON中定位特定键值对的最优实现方式
现有一个结构复杂的深层嵌套JSON,需从中定位包含键值对"domain": "pack"的对象,该键的路径示例为item.items.offerings.item.items.offers.item.items.offers.domain。难点在于items和offers均为包含多个对象的数组,且每个对象都包含item,需遍历数组内的每个对象进行搜索。
已实现如下递归函数且运行正常,但不确定是否为最优方案,现咨询:不借助任何库的情况下,是否有更优的实现方式?
function findDomain(obj) { if (obj && typeof obj === 'object') { if (obj.domain === 'pack') { return obj; } let found = false; let result; for (const key in obj) { if (obj.hasOwnProperty(key) && !found) { const value = obj[key]; const childResult = findDomain(value); if (childResult) { found = true; result = childResult; } } } return result; } return null; } const pack = findDomain(a); console.log(pack); //a is the object
优化实现方案
你的递归实现逻辑是正确的,但存在栈溢出风险——当JSON嵌套层级极深时,递归调用会超出JavaScript的调用栈限制(通常在几千层左右)。不借助第三方库的情况下,用**迭代式的深度优先搜索(DFS)或广度优先搜索(BFS)**是更优的选择,既避免栈溢出,也能保持提前终止遍历的特性。
迭代式DFS实现(推荐,和原递归逻辑一致但更安全)
function findDomainIterative(obj) { // 用栈模拟递归调用,栈元素为待遍历的对象 const stack = [obj]; while (stack.length > 0) { const current = stack.pop(); // 跳过非对象/数组的元素 if (!current || typeof current !== 'object') continue; // 找到目标直接返回 if (current.domain === 'pack') { return current; } // 处理数组:将数组元素倒序压栈(保证遍历顺序和递归一致) if (Array.isArray(current)) { // 倒序压栈,保证正序遍历(栈是后进先出) for (let i = current.length - 1; i >= 0; i--) { stack.push(current[i]); } } else { // 处理普通对象:遍历自身可枚举属性,压入栈 for (const key in current) { if (current.hasOwnProperty(key)) { stack.push(current[key]); } } } } // 未找到目标 return null; } const pack = findDomainIterative(a); console.log(pack);
优化点说明
- 避免栈溢出:迭代用堆内存中的栈数组代替调用栈,不受JS调用栈深度限制,能处理极深嵌套的JSON。
- 提前终止:找到目标对象后立即返回,无需遍历剩余节点,和原递归的效率一致。
- 统一处理数组和对象:明确区分数组和普通对象的遍历逻辑,比原递归中自动遍历数组元素(因为数组也是对象,key是索引)的方式更清晰,避免不必要的属性检查。
- 性能更稳定:递归在深层嵌套时会产生大量调用栈帧,迭代的内存占用更可控。
可选:BFS实现(适合优先找浅层的目标对象)
如果你的JSON中目标对象可能出现在浅层,BFS可以更快找到结果:
function findDomainBFS(obj) { const queue = [obj]; while (queue.length > 0) { const current = queue.shift(); if (!current || typeof current !== 'object') continue; if (current.domain === 'pack') { return current; } if (Array.isArray(current)) { queue.push(...current); } else { for (const key in current) { if (current.hasOwnProperty(key)) { queue.push(current[key]); } } } } return null; }
内容的提问来源于stack exchange,提问作者Lelouch
相关产品推荐
相关产品推荐

