通过递归算法对执行栈的理解
如果是数据1 的这种结构,就使用递归遍历数据即可,对于数据2 则需要先将打平的数据转化为 数据1 的格式。
将下面结构转为树形结构
[
{
id: 1,
pid: '',
name: '北京市'
},
{
id: 2,
pid: 1,
name: '海淀区'
},
{
id: '2-2',
pid: 2,
name: '知春路'
},
{
id: '2-3',
pid: 2,
name: '中关村'
},
{
id: '2-1',
pid: 2,
name: '西二旗'
},
{
id: 3,
pid: 1,
name: '昌平区'
},
{
id: '3-1',
pid: 3,
name: '回龙观'
},
{
id: '3-2',
pid: 3,
name: '朱辛庄'
},
{
id: 4,
pid: 1,
name: '朝阳区'
},
{
id: '4-2',
pid: 4,
name: '三元桥'
},
]
function arrToTree(list, rootValue) {
let treeData = [] // 新建数组 , 用来储存当前对象的子对象
list.forEach(item => {
// 遍历寻找子对象
if (item.pid === rootValue) {
// 递归 返回对象的children列表
const children = arrToTree(list, item.id)
// 如果有children就将数组添加给对象
if (children.length) {
item.children = children
}
// 将完整的item添加给导出的数组
treeData.push(item)
}
})
return treeData // 每次递归会返回当前的子列表
}
const treeData = arrToTree(list, '')
上面执行 过程中,首先创建全局的执行栈 arrToTree 执行的时候, push 到执行栈中,在它的作用域内遍历list, 判断 list中元素的pid 是不是等于传入的rootValue 如果等于, 就递归执行 arrToTree, 将新的 rootValue 传入,生成一个新的函数作用域,push 到执行栈中, 依次递归执行,一直到 不满足 item.pid === rootValue ,函数执行完 返回 treeData 然后 pop 出执行栈。
如果还是不清楚,可以按照下面的思路 自己理解下
1. 创建全局执行栈
2. arrToTree 函数push 到执行栈 函数接收的参数是 list, '' .下面元素
{
id: 1,
pid: '',
name: '北京市'
},
满足条件,所以递归执行了arrToTree 参数为 list, 1
3. arrToTree 函数push 到执行栈 此时执行栈是这样的
[全局上下文,第二部函数执行上下文, 第三步函数执行上下文]
此时还是遍历list
下面元素
{
id: 2,
pid: 1,
name: '海淀区'
},
满足条件, 所以递归执行了arrToTree 参数为 list, 2
4. arrToTree 函数push 到执行栈
此时执行栈是这样的
[全局上下文,第二部函数执行上下文, 第三步函数执行上下文,第四步函数上下文]
此时还是遍历list
下面元素
{
id: '2-2',
pid: 2,
name: '知春路'
},
满足条件,所以递归执行了arrToTree 参数为 list, 2-2
5. arrToTree 函数push 到执行栈
此时执行栈是这样的
[全局上下文,第二部函数执行上下文, 第三步函数执行上下文,第四步函数上下文,第五步函数上下文]
此时还是遍历list , 这个时候 没有元素满足条件 所以函数返回了[]. 并且将该上下文 pop 出执行栈 也就回到了第四步执行上下文, 第四步中的 treeData 应为第五步返回的是空数组就push 了
{
id: '2-2',
pid: 2,
name: '知春路'
},
在第四步的上下文中继续遍历 第二个符合条件的是
{
id: '2-3',
pid: 2,
name: '中关村'
},
递归执行了arrToTree 参数为 list, 2-3
在执行栈中添加新的上下文,继续执行,发下没有满足条件的,返回了空数组, 再pop 出执行栈,然后应为返回的是空数组, 所以将元素中关村的内容 也push 到 第四步的执行上下文 treeData,
接着遍历 发现 西二旗 的内容也满足, 重复上面的步骤,最后 返回第四步的上下文后,此时 treeData 中有 知春路,中关村,西二旗三组数据,第四步上下文没有满足条件的情况下 返回 treeData ,将第四步上下文 pop 出执行栈, 来到第三步执行栈, 应为返回的treeData.length > 0 给该执行栈 当前元素 海淀区 创建一个key ="children" ,value= treeData
第三步执行栈中接着遍历, 发现下一个满足条件的元素 name 为 昌平区 ,重复上面第四步的步骤
。。。
第三步执行栈中接着遍历, 发现下一个满足条件的元素 name 为 朝阳区 ,重复上面第四步的步骤
第三步上下文执行完后,pop 出执行栈,返回 trueData
没有满足第三步条件的情况下, 将 第三步上下文 pop 出执行栈
接着执行 第二部执行栈 最后执行完后 再pop 出执行栈,
到全局执行栈的时候, 也就返回了最终的结果