我们有时会遇到树形节点,而树形节点有时和动态路由有关系。有的时候还需要我们自己找到对应的值。那么怎样从数据节点中找到指定 id 的节点?
这个时候就需要用到 尾递归(tail recursion 或 tail-end recursion)。
尾递归是一种在函数的最后执行递归调用语句的特殊形式的递归。
一些语言提供了尾递归优化。这意味着如果一个函数返回自身递归调用的结果,那么调用的过程会被替换为一个循环,它可以显著提高速度。遗憾的是,JavaScript 当前并没有提供尾递归优化。深度递归的函数可能会因为堆栈溢出而运行失败。———JavaScript 语言精粹 (2008年版本)
所以,一定要做好容错处理。
回到最开始说的,树形节点的数据结构如下:
var menu = [
{
id: '1',
children: [
{id: '1-1'}
]
},
{
id: '2',
children: [
{
id: '2-1'
},
{
id: '2-2',
children: [
{id: '2-2-1'},
{
id: '2-2-2',
children: [
{id: '2-2-2-1'},
{id: '2-2-2-2'}
]
}
]
}
]
}
]
使用尾递归的方式:
function findNode(list, id) {
list = list || [];
var allChildren = []; // 保存同级的所有节点
var node = null; // 存找到的节点
// 这里不建议用 forEach,forEach 没有办法中途 break,会白白的占用主线程。
for (var i = 0; i < list.length; i++) {
// 如果找到了退出循环,同时存 node,后面使用
if (list[i].id === id) {
node = list[i];
break;
}
allChildren.push(...list[i].children || [])
}
if (node || allChildren.length === 0) {
return node; // node 为 找到的值或者 null
}
return findNode(allChildren, id)
}
运行、测试:
console.log(findNode()) // null
console.log(findNode(menu, '2-2-2-2')) // {id: '2-2-2-2'}
console.log(findNode(menu, '3-3-3-3-3')) // null
如果有错误或者更好的写法,欢迎留言。