JS递归-过滤数组函数

2,436 阅读2分钟

今天同事在做一个树形结构数据,需要过滤掉数组中不合法的项。具体示例如下面代码中的 json 结构,需要过滤到所有 isFolder 值为0的项。

第一次写居然错了,只导出最下面一层,晚上自己琢磨了一下改了改,用是可以用了,但是注释部分自己都有点不太明白。

简单做个记录,以后有时间再研究一下递归函数。

/**
 * 过滤数组不合法项
 * @param {Array} arr 传入目标数组 
 * @returns 过滤后的数组
 * ?不是常规的递归函数,但是结果是正常的。
 */
let recurData = (arr) => {
  // 用一个变量来记录传入数组当前层次过滤后的集合。
  let tempArr = arr.filter(item => !!item.isFolder)

  // 循环遍历,有children的项,并递归
  for (let item of tempArr) {
    if (item.children && item.children.length) {
      // 这里是关键,相当于是修改当前层次的children,递归以后就不会影响上一层的数据而且永远是修改的下一层的数据。
      item.children = recurData(item.children)
    }
  }

  // 这里导出第一次过滤后的数据,但是for循环是同步运行的,所以只有递归结束以后才会触发return,当数据量大时性能会下降。
  return tempArr
}

let json = [
  {
    id: 1, isFolder: 1, children: [
      { id: '1-2', isFolder: 0 },
      { id: '1-3', isFolder: 1 },
      {
        id: '1-4', isFolder: 1,
        children: [
          { id: '1-4-1', isFolder: 1 },
          { id: '1-4-2', isFolder: 0 },
          { id: '1-4-3', isFolder: 1 },
          { id: '1-4-4', isFolder: 0, }
        ]
      },
    ]
  },
  { id: 2, isFolder: 0 },
  { id: 3, isFolder: 1 },
  { id: 4, isFolder: 0 },
  { id: 5, isFolder: 1 },
]

let result = recurData(json)
console.log(JSON.stringify(result))

//[{"id":1,"isFolder":1,"children":[{"id":"1-3","isFolder":1},{"id":"1-4","isFolder":1,"children":[{"id":"1-1-1","isFolder":1},{"id":"1-1-3","isFolder":1}]}]},{"id":3,"isFolder":1},{"id":5,"isFolder":1}]

再附录上第一次写错的玩意:

function treeDataInit(treeData) {
    
    let recurData = (arr) => {
        let tempArr = arr.filter(item => !!item.isFolder)
        let num = 0
        for (let item of tempArr) {
            if (item.children && item.children.length) {
                num ++
                return recurData(item.children)
            }
        }
        if(num === 0){
            return tempArr
        }
    }
    let TArr = recurData(treeData)
    console.log(TArr)
}

let json = [
    {
        id1isFolder1children: [
            { id'1-2'isFolder0 },
            { id'1-3'isFolder1 },
            { id'1-4'isFolder0 },
        ]
    },
    { id2isFolder0 },
    { id3isFolder1 },
    { id4isFolder0 },
    { id5isFolder1 },
]
treeDataInit(json)

//[ { id: '1-3', isFolder: 1 } ]

理一下写错的这个的思路:

  1. 先把传入的数组进行过滤,并用一个变量保存。
  2. 写一个计数器,用来记录是当前数组下是否有children,没有的话退出递归。
  3. 当有children时,进入递归。

简单来看,是没有问题的,但是每次都在 return tempArr 的话,就会把上一次计算结果给覆盖掉,所以最终结果就是只有最下层的了,而且可以预料到的是,是最后一项最下一层的结果。

而正确的写法中,一直在导出下一层的数据,所以不会影响到当前层。