前言:
今天兄弟们对“树的展示js”可能比较看重,朋友们都想要剖析一些“树的展示js”的相关内容。那么小编同时在网摘上汇集了一些关于“树的展示js””的相关资讯,希望小伙伴们能喜欢,你们一起来学习一下吧!前言
数组转树,算是一个很平常的问题。网上搜一搜,都能找到答案。知原理,会递归,会循环基本都能写出来,但是我们今天为什么要写这篇文章呢?肯定是遇到了特殊的问题。现在,请看下面的例子。
举例:
方式一:递归
const arrayTosTree = (data: any, idCode: string, pidCode: string, childCode: any, pidData: string) => { let result: any = []; data.forEach((item: any) => { if (item[pidCode] == pidData) { const children = arrayTosTree(data, idCode, pidCode, childCode, item[idCode]); children.length && (item[childCode] = children); result.push(item); } }); return result;}const results = arrayTosTree(datas, 'id', 'pid', 'children', '');console.log(JSON.stringify(results));
在数据量比较少时,不需要考虑重复循环的问题,反正也很快。所以这种方式还是不错的,因为就算数据先后顺序不一致时,它也能得到我们想要的结果。
比如:
方式二:map
优化性能问题(循环次数),同时支持方式一中的两种情况。
const arrayTooTree = (datas: any[], idCode: string, pidCode: string, childCode: any, pidData: string) => { let result: any[] = []; let map: any = {}; // 缓存数据 datas.forEach((item: any) => { item[childCode] = []; map[item[idCode]] = item; }); // 构建tree datas.forEach((item: any) => { let id = item[idCode]; let pid = item[pidCode]; if (pid === pidData) { result.push(map[id]); } else { map[pid][childCode].push(map[id]); } }) return result;}
这种方式堪称完美,数据量比较大时,性能也非常不错。
到此并没有结束,请看下面的需求。
假设,现在要做一个搜索功能,也就是根据名称搜索,显示被搜索项以及它的子项,可能出现下面的情况。
搜索:子
执行结果:筷子、木筷、勺子、箱子不见了。
这里我是故意少写了一句代码,主要就是为了描述这种情况。当然您可以根据实际需求来决定,是否添加这行代码,或者添加一个启用或禁用的参数。
const arrayTooTree = (datas: any[], idCode: string, pidCode: string, childCode: any, pidData: string) => { let result: any[] = []; let map: any = {}; // 缓存数据 datas.forEach((item: any) => { item[childCode] = []; map[item[idCode]] = item; }); // 构建tree datas.forEach((item: any) => { let id = item[idCode]; let pid = item[pidCode]; if (pid === pidData) { result.push(map[id]); } else { // 借用对象的引用来实现 if (!map[pid]) { map[pid] = { children: [] }; result.push(map[id]); } map[pid][childCode].push(map[id]); } }) return result;}
到此您以为就结束了吗,还是没有。
方式二中我们看到,对原数组进行了两次循环,那么还可以更进一步优化吗?
方式三:进阶
const arrayToTree = (data: any, idCode: string, pidCode: string, childCode: any, pidData: string) => { let result: any = []; let map: any = {}; let objState: any = (() => { function d() { } return new (d as any)(); })(); data.forEach((item: any) => { // 初始化 const sid = item[idCode]; const pid = item[pidCode]; objState.__proto__[sid] = 1; map[sid] = Object.assign(item, map[sid] || {}); if (pid !== pidData) { let parent = map[pid] || {}; parent[childCode] || (parent[childCode] = []); parent[childCode].push(item); objState[pid] !== 1 && (objState[pid] = 0); objState[sid] === 0 && (objState[sid] = 1); map[pid] = parent; } else { objState[sid] = 1; result.push(map[sid]); } }); Object.keys(objState).map( (key) => { console.log(key, objState[key]); objState[key] === 0 && result.push.apply(result, map[key][childCode]); } ); return result;}
方式三,其实为方式二的优化版,通过使用__proto__尽量减少了循环次数。当然这不是结束,至少方式三的代码还可以进一步优化。
文章最后代码示例截图,已Typescript化处理,感谢友友指出。
人人为我,我为人人,欢迎您的浏览,我们一起加油吧。
标签: #树的展示js