js 将线性对象转化为树型对象

195 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

前言

这是一个常见的内容,如何将线性的数据转化为树型对象,我们需要一种思路,一种递归的思想,本文主要是介绍这种思想。

完整代码和结果

  const arr = [
    { name: '内容1', fid: 0, id: 0, },
    { name: '内容2', fid: 0, id: 1, },
    { name: '内容3', fid: 0, id: 2, },
    { name: '内容4', fid: 1, id: 3, },
    { name: '内容5', fid: 1, id: 4, },
    { name: '内容6', fid: 2, id: 5, },
  ]

  const res = []


  // 两个入参 一个是线性对象数组,一个是目标对象
  const addChild = (arr, obj) => {
    // 目标对象的fid
    const { fid } = obj
    // 遍历线性对象数组
    arr.forEach(cur => {
      // 取出遍历的对象的id
      const { id } = cur
      // 判断是否是目标对象的fid
      if (fid === id) {
        // 如果是,先判断加上child指针
        cur.child ? null : cur.child = []
        // 如果加过了,直接加进子级数组
        cur.child.push(obj)
      } else if (cur.child) {
        // 存在子级对象数组,就得判断子级有没有目标对象的父级
        addChild(cur.child, obj)
      }
    });
  }

  arr.map(cur => {
    const { id, fid } = cur
    if (id === fid) {
      res.push(cur)
    } else {
      addChild(res, cur)
    }
  })

  console.log(res)

在这里插入图片描述

思想理解

我肯定不能保证你的线性数据结构与我这里的相同,因此我们重点是掌握一种递归的思路,怎么一步步完成。

创建线性数据

在创建线性数据时我们就应该为树状数据的转化做准备,什么准备呢?

  const arr = [
    { name: '内容1', fid: 0, id: 0, },
    { name: '内容2', fid: 0, id: 1, },
    { name: '内容3', fid: 0, id: 2, },
    { name: '内容4', fid: 1, id: 3, },
    { name: '内容5', fid: 1, id: 4, },
    { name: '内容6', fid: 2, id: 5, },
  ]

比如我创造一个这样的数据,fid表示它父级节点的id。

特点就是id按顺序排列,且父节点的id会小于子节点的id。

这样我们就可以很容易的生成树状结构,不必担心自己的父级节点比自己晚遍历到,不会造成找不到父级节点的情况。

创建一个结果数组

  const res = []

找到根节点

我们创建了结果数组,树也许不好整,但是把根种下去还是容易吧。

比如你可以提前标好type,我这里是定义自己id与fid相等的为根节点。

我们遍历数据,把定义好的根加入

  arr.map(cur => {
    const { id, fid } = cur
    if (id === fid) {
      res.push(cur)
    } else {
      ...
    }
  })

接下来就是考虑..到底是什么呢,如果不是根,那这个目标对象就是有父节点的了。

既然有父节点,我们就把结果数组遍历一遍找找有没有对应的目标对象的父节点。

我们就需要创建一个找父级的方法。

可能需要两个入参,一个结果数组也就是一个对象数组,和一个正在找父级的目标对象

  addChild(arr,obj)

创建递归方法

我们希望在一个线性的对象数组里找到其中的一个对象,是我们某个目标对象的父级节点。

如果是找到了,就给父级节点加入子级指针指向目标对象。

  // 两个入参 一个是线性对象数组,一个是目标对象
  const addChild = (arr, obj) => {
    // 目标对象的fid
    const { fid } = obj
    // 遍历线性对象数组
    arr.forEach(cur => {
      // 取出遍历的对象的id
      const { id } = cur
      // 判断是否是目标对象的fid
      if (fid === id) {
        // 如果是,先判断加上child指针
        cur.child ? null : cur.child = []
        // 如果加过了,把目标对象直接加进遍历对象的子级数组
        cur.child.push(obj)
      } 
    });
  }

如果不是呢?不是的话就不加了吗,肯定不行。

因为即便当前的遍历对象不是目标对象的父级节点,我们不能保证遍历对象的子级对象数组中没有目标对象的节点。

那么怎么判断子级对象数组有没有呢?

我们发现又是在一个对象数组里面找,所以我们还是调用同样的方法,这就是递归了。


  // 两个入参 一个是线性对象数组,一个是目标对象
  const addChild = (arr, obj) => {
    // 目标对象的fid
    const { fid } = obj
    // 遍历线性对象数组
    arr.forEach(cur => {
      // 取出遍历的对象的id
      const { id } = cur
      // 判断是否是目标对象的fid
      if (fid === id) {
        // 如果是,先判断加上child指针
        cur.child ? null : cur.child = []
        // 如果加过了,直接加进子级数组
        cur.child.push(obj)
      } else if (cur.child) {
        // 存在子级对象数组,就得判断子级有没有目标对象的父级
        addChild(cur.child, obj)
      }
    });
  }

尾言

如果觉得文章对你有帮助的话,欢迎点赞收藏哦,有什么错误或者意见建议也可以留言,感谢~