来源
相信前端的小伙伴在做项目的时候肯定会遇到各种数据结构,接下来我们讲的就是一种Tree结构,在项目种还是比较实用的,例如:部门树、侧边栏的菜单树等,她可能是下面的这个样子
let treeData = [ { name: 'a', title: 'a', children: [ { name: 'a-1', title: 'a-1', children: null }, { name: 'a-2', title: 'a-2', children: [ { name: 'a-2-1', title: 'a-2-', children: null }, { name: 'a-2-2', title: 'a-2-2', children: null }, ] }, { name: 'a-3', title: 'a-3', children: null }, ] }, { name: 'b', title: 'b', children: [ { name: 'b-1', title: 'b-1', children: null }, { name: 'b-2', title: 'b-2', children: [ { name: 'b-2-1', title: 'b-2-1', children: null }, { name: 'b-2-2', title: 'b-2-2', children: null }, ] }, ] }]前后端分离的时代既然有了数据了,那我们就要将它可视化的展示给我们的用户,以上面的代码结构为例,我们取值所有的name属性,实际应用中可能是个部门名称哦~,
遍历这种数据结构分为两种方式,他们分别是BFS与DFS(这两种遍历方式不懂的可以自行查阅,看到结尾估计就能理解了,这里不多做介绍~)
DFS实现:
看到网上有很多的实现方式,咱们这里简化处理将代码量缩减,使代码更加简洁
一、递归遍历方式
function getNames (data) {
let arrayArguments = [...arguments][1]
let preArray = arrayArguments? arrayArguments : []
data.map(({name, children}) => {
name? preArray.push(name) : null
children ? getNames(children, preArray): null
})
return preArray
}这里使用argument这个为数组,来获取函数的参数,来避免显性的传入第二个参数,还有就是来避免外部变量的声明,将变量放在函数体内,防止全局污染,例如这种
getNames (data,list=[])因为这里我们只用到两个参数,所以就直接用下标来取值[...arguments][1]
二、非递归遍历方式
function getNames (data) {
let names = []
let stackItem = {}
let stack = data.map(item => {
return item
})
while (stack.length) {
stackItem = stack.shift()
names.push(stackItem.name)
stack = stackItem.children? [...stackItem.children,...stack]: stack } return names
}非递归的方式我们将传入的数据(一般是引用类型),进行拷贝,重新开辟一份内存空间,防止污染传入的数据,因为数组的shift()方法会改变原有的数组结构,所以这里while循环体内数组的长度来判断什么时候结束循环,循环体内根据是否存在下级的children进行stack新数组的操作,两种方式的遍历结果如下:
BFS实现:
BFS的实现方式和DFS非递归方式雷同,在实现方式上我们只去改变一下这里就可以了
DFS非递归方式数组合并
stack = stackItem.children? [...stackItem.children,...stack]: stack }
BFS非递归方式数组合并
stack = stackItem.children? [...stack, ...stackItem.children]: stack } 只需要将合并数组的顺序颠倒 就可以产生不同的效果,打印结果如下:
相信根据打印结果大家就能理解到BFS与DFS的差别,这里没有想到BFS递归实现的好方法,如果你有好的方法,欢迎指导~