原数组(在本例中顺序不影响结果)
let tree = [
{ id: 1, pid: 'root', name: '1' },
{ id: 2, pid: 1, name: '2' },
{ id: 3, pid: 1, name: '3' },
{ id: 4, pid: 'root', name: '4' },
{ id: 5, pid: 4, name: '4' },
{ id: 6, pid: 4, name: '5' },
{ id: 7, pid: 3, name: '7' },
{ id: 8, pid: 4, name: '8' },
]
实现方法(使用filter实现)
function ListToTree(data) {
// 简单对象的深度拷贝
let cloneData = JSON.parse(JSON.stringify(data))
// 两层嵌套的filter
return cloneData.filter(father => {
// 子结构分支
let branchArr = cloneData.filter(child => father['id'] == child['pid']);
// console.log(`father key is ${father.id}`+JSON.stringify(branchArr)+"\n")
branchArr.length > 0 ? father['children'] = branchArr : '';
// 只需要返回根节点的元素
return father['pid'] == 'root';
})
}
//使用
let newTree = ListToTree(tree)
console.log(JSON.stringify(newTree));
引发的思考:两层filter循环应该只能处理两层树结构,但事实证明,这是多虑的。
进行测试:
console.log(`father key is ${father.id}`+JSON.stringify(branchArr)+"\n")
把ListToTree函数中的测试注释使用上,结果如下:
father key is 1 and branch is:[{"id":2,"pid":1,"name":"2"},{"id":3,"pid":1,"name":"3"}]
father key is 2 and branch is:[]
father key is 3 and branch is:[{"id":7,"pid":3,"name":"7"}]
father key is 4 and branch is:[{"id":5,"pid":4,"name":"4"},{"id":6,"pid":4,"name":"5"},{"id":8,"pid":4,"name":"8"}]
father key is 5 and branch is:[]
father key is 6 and branch is:[]
father key is 7 and branch is:[]
father key is 8 and branch is:[]
我们发现:
1.遍历到 father.id = 1 时,branch中的id=3子节点是没有children的;
2.遍历到 father.id = 3 时, 它才拥有了子节点(children数组)
3.这似乎无济于事,因为第一步已经执行并返回了数组,结果就应该是只有两层树结构
4.根据结果来看,就算是第一步先执行并先返回,也会被后续的更改所影响
猜测:这时我们可以猜测这里的filter是对数组元素----对象的引用
证明:
let testItem = tree.filter(item=>{
return item.id == 3
})
console.log(testItem[0] === tree[2])
结果:为True,所以他们的地址值相等,也就是filter返回的数组元素是对原数组元素中的地址的引用。
至此我们也清楚了filter的原理以及如何将List转为Tree