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; };
这里的问题有两个:
- 默认参数
path = []只会在第一次调用时创建数组,后续递归都复用同一个引用; - 如果用了
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
相关产品推荐
相关产品推荐

