一.前言
在实际开发中,对树形JSON数据处理的业务场景非常常见;而且这些数据必然是多层级的,那么很重要的一点就是要做到递归。特别是在动态路由筛选和树形结构数据筛选中。正所谓,“工欲善其事,必先利其器”。所以本文总结几种用于处理得到我们业务中所需的真正数据的方法。
二.实现方法
- “splice”方法 (不推荐):
-
说明:这种方法只适应于唯一性的条件(比如:过滤唯一性id)的场景。
如果是用在筛选树形数据或者路由菜单(比如:过滤hidden为true)的场景,会因为其实正向删除index值,故导致第一次除外的每次遍历递归的index值不准确,所以删除的值也是不对的,故不推荐。 -
代码实现:
//只适用于唯一性的id的递归过滤
function filterData(arr, id) {
arr.forEach((item, index) => {
if (item.id === id) {
arr.splice(index, 1)
}
if (item.children && item.children.length) {
filterData(item.children, id)
}
})
}
- 纯“filter”方法 (推荐):
- 代码实现:
// 递归过滤得到每一项的hidden为false的数据
function filterData2(arr) {
return arr.filter(item => {
if (item.children) {
item.children = filterData2(item.children)
}
if (!item.hidden) {
return true
}
})
}
- “filter”加“map”方法 (推荐):
- 代码实现:
//深拷贝
function deepCopy(params) {
// 如果不是对象则退出(可停止递归)
if (typeof params !== 'object') return;
// 深拷贝初始值:对象/数组
let newObj = (params instanceof Array) ? [] : {};
// 使用 for-in 循环对象属性(包括原型链上的属性)
for (let i in params) {
// 只访问对象自身属性
if (params.hasOwnProperty(i)) {
// 当前属性还未存在于新对象中时
if (!(i in newObj)) {
if (params[i] instanceof Date) {
// 判断日期类型
newObj[i] = new Date(params[i].getTime());
} else if (params[i] instanceof RegExp) {
// 判断正则类型
newObj[i] = new RegExp(params[i]);
} else if ((typeof params[i] === 'object') && params[i].nodeType === 1) {
// 判断 DOM 元素节点
let domEle = document.getElementsByTagName(params[i].nodeName)[0];
newObj[i] = domEle.cloneNode(true);
} else {
// 当元素属于对象(排除 Date、RegExp、DOM)类型时递归拷贝
newObj[i] = (typeof params[i] === 'object') ? deepCopy(params[i]) : params[i];
}
}
}
}
return newObj;
}
// 递归过滤得到每一项的hidden为false的数据
function filterData3(arr){
return arr.filter(item => {
return !item.hidden
}).map(i => {
i = deepCopy(i)
if (i.children) {
i.children = filterData3(i.children)
}
return i
})
}
三.文末
感兴趣的童靴可以根据自己项目自行测试和使用。当然,实现的方法还有很多,重要的是掌握其中递归遍历的思想。如大佬们有更有优秀的实现方法,还请多多指教。