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

JavaScript递归函数报错排查:获取查询ID全路径异常问题

解决递归获取节点路径时的重复id问题

看起来你遇到的是递归中数组引用共享导致的路径被重复修改问题,我来帮你排查并给出正确的实现方式。

问题根源分析

你提到返回[6,6,6],大概率是因为你的递归函数里复用了同一个数组引用——比如把路径数组作为默认参数传递,或者在函数外部声明了路径数组,导致每次递归调用都修改同一个数组,最终重复添加了目标节点的id。

举个典型的错误写法例子(应该和你的代码类似):

// 错误示例:共享数组引用导致路径被污染
const getPath = (id, list, path = []) => {
  if (!list || !Array.isArray(list)) return path;
  
  for (var node of list) { // 这里用var也可能导致变量覆盖问题
    if (node.id === id) {
      path.push(node.id);
      return path;
    }
    const childPath = getPath(id, node.children, path);
    if (childPath.length) {
      path.push(node.id);
      return path;
    }
  }
  return path;
};

这里的问题有两个:

  1. 默认参数path = []只会在第一次调用时创建数组,后续递归都复用同一个引用;
  2. 如果用了var node,变量会被提升到函数作用域,递归时node的值会被循环的后续迭代覆盖。

正确的递归实现

我们需要保证每个递归层级都创建独立的路径数组,找到子路径后把当前节点id前置到子路径中:

const getPath = (targetId, nodes) => {
  // 边界处理:非数组直接返回空路径
  if (!Array.isArray(nodes)) return [];

  for (const node of nodes) {
    // 找到目标节点,返回仅包含当前id的数组
    if (node.id === targetId) {
      return [node.id];
    }

    // 递归查找子节点的路径
    const childPath = getPath(targetId, node.children);
    // 子路径存在,说明目标在当前节点的子树中,拼接当前id和子路径
    if (childPath.length > 0) {
      return [node.id, ...childPath];
    }
  }

  // 遍历完所有节点未找到,返回空数组
  return [];
};

这个实现的核心是:每次递归返回的都是新数组(通过扩展运算符...创建),不会和其他递归层级共享引用,因此不会出现路径被覆盖的问题。测试getPath(6, rawData)会正确返回[1,2,6]。

迭代实现方案(避免递归栈溢出)

如果你的节点树层级很深,递归可能会导致栈溢出,这时可以用迭代版的深度优先搜索(DFS)来实现:

const getPath = (targetId, nodes) => {
  if (!Array.isArray(nodes)) return [];

  // 栈中存储当前节点和对应的路径
  const stack = nodes.map(node => ({ currentNode: node, currentPath: [node.id] }));

  while (stack.length > 0) {
    const { currentNode, currentPath } = stack.pop();

    // 找到目标节点,直接返回路径
    if (currentNode.id === targetId) {
      return currentPath;
    }

    // 子节点倒序入栈,保证遍历顺序和递归一致
    if (Array.isArray(currentNode.children)) {
      for (let i = currentNode.children.length - 1; i >= 0; i--) {
        const child = currentNode.children[i];
        stack.push({
          currentNode: child,
          currentPath: [...currentPath, child.id]
        });
      }
    }
  }

  // 未找到目标节点
  return [];
};

这个版本用栈模拟递归过程,每次处理节点时都创建新的路径数组,同样避免了引用共享的问题,同时适合处理深层级的节点树。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:37:47