使用JavaScript实现DFS无法获取目标记录,递归理解存疑
嘿,我完全懂递归和DFS混在一起的时候有多绕——尤其是对着你这种嵌套得很深的披萨对象时,很容易摸不着头绪。咱们一步步来拆解,先把递归的逻辑掰明白,再针对你的对象写能拿到想要记录的DFS实现。
先搞懂递归到底在干嘛
递归说白了就是函数自己调用自己,但绝不是瞎调用,必须抓住两个核心:
- 终止条件:什么时候停止调用自己,不然会无限循环导致栈溢出
- 拆解问题:把大问题拆成和原问题一模一样的小问题,每次调用只处理一小部分
放到你的场景里:大问题是“在整个嵌套对象里找披萨记录”,小问题就是“检查当前的子对象/数组元素,如果是披萨就收集/返回,如果是嵌套结构就继续往里钻”。
针对你的披萨对象实现DFS
先明确你的对象结构:obj → pizze → typeOne → data 里存着所有披萨的数组。下面分两种常见需求写实现:
需求1:收集所有披萨记录
如果要把所有披萨都捞出来,DFS的思路是遍历每个节点,碰到披萨就加入结果,碰到嵌套结构就递归进去:
let obj = { pizze:{ type:"pizze", typeOne:{ title: "Pizze Rosse", data:[ {id:1,type:"pizza",name:"Margherita",price:4,ingredients:["pomodoro","mozzarella"],quantity:0,inventory:100}, {id:2,type:"pizza",name:"Marinara",price:3.5,ingredients:["aglio","pomodoro"],quantity:0,inventory:100}, {id:3,type:"pizza",name:"Salsiccia e funghi",price:6,ingredients:["salsiccia","funghi","mozzarella","pomodoro"],quantity:0,inventory:100} ] } } }; function collectAllPizzas(node) { let result = []; // 终止条件1:节点不存在,直接返回空数组 if (!node) return result; // 找到披萨了,加入结果 if (typeof node === 'object' && node.type === 'pizza') { result.push(node); } // 如果是数组,遍历每个元素递归处理 if (Array.isArray(node)) { for (const item of node) { result = result.concat(collectAllPizzas(item)); } } // 如果是普通对象,遍历每个属性值递归处理 else if (typeof node === 'object') { for (const key in node) { result = result.concat(collectAllPizzas(node[key])); } } return result; } // 调用测试 const allPizzas = collectAllPizzas(obj); console.log(allPizzas); // 会输出所有3个披萨对象
需求2:根据ID查找单个披萨
如果要找特定ID的披萨,找到后可以直接终止递归返回,不用继续遍历:
function findPizzaById(node, targetId) { // 终止条件1:节点不存在,返回null if (!node) return null; // 找到目标披萨,直接返回 if (typeof node === 'object' && node.type === 'pizza' && node.id === targetId) { return node; } // 数组遍历:对每个元素递归查找,找到就立刻返回 if (Array.isArray(node)) { for (const item of node) { const foundPizza = findPizzaById(item, targetId); if (foundPizza) return foundPizza; } } // 对象遍历:对每个属性值递归查找,找到就立刻返回 else if (typeof node === 'object') { for (const key in node) { const foundPizza = findPizzaById(node[key], targetId); if (foundPizza) return foundPizza; } } // 遍历完所有节点都没找到,返回null return null; } // 调用测试 const margherita = findPizzaById(obj, 1); console.log(margherita); // 会输出ID为1的Margherita披萨对象
再顺一遍递归的执行流程(以找ID=1为例)
- 第一次调用
findPizzaById(obj, 1),遍历顶层对象的pizze属性 - 调用
findPizzaById(obj.pizze, 1),遍历这个对象的typeOne属性 - 调用
findPizzaById(obj.pizze.typeOne, 1),遍历这个对象的data属性 - 调用
findPizzaById(obj.pizze.typeOne.data, 1),这是数组,遍历第一个元素(ID=1的披萨) - 调用
findPizzaById(data[0], 1),发现这个对象符合条件,直接返回它 - 结果一层层往上传递,最终你就拿到了目标披萨
这样是不是就清晰多了?递归就是每一步只专注当前节点,把剩下的交给下一次自己调用,直到触发终止条件。
内容的提问来源于stack exchange,提问作者Giacomo Ciampoli
相关产品推荐
相关产品推荐

