You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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为例)
  1. 第一次调用findPizzaById(obj, 1),遍历顶层对象的pizze属性
  2. 调用findPizzaById(obj.pizze, 1),遍历这个对象的typeOne属性
  3. 调用findPizzaById(obj.pizze.typeOne, 1),遍历这个对象的data属性
  4. 调用findPizzaById(obj.pizze.typeOne.data, 1),这是数组,遍历第一个元素(ID=1的披萨)
  5. 调用findPizzaById(data[0], 1),发现这个对象符合条件,直接返回它
  6. 结果一层层往上传递,最终你就拿到了目标披萨

这样是不是就清晰多了?递归就是每一步只专注当前节点,把剩下的交给下一次自己调用,直到触发终止条件。

内容的提问来源于stack exchange,提问作者Giacomo Ciampoli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:56:12