JavaScript实现无限级递归树的示例代码

需求

最近遇到一个需求,平时被后台惯着直接返回了树形结构给到前端,前端对这种嵌套类型的数据(如地区的级联或菜单的树形结构)省掉了一层处理。换了个后台开发返回了扁平化的数组数据给到前端自己去处理如下data。突然有点慌......

const data = [
  {
    "area_id": 5,
    "name": "广东省",
    "parent_id": 0,
  },
  {
    "area_id": 6,
    "name": "广州市",
    "parent_id": 5,
  },
  {
    "area_id": 7,
    "name": "深圳市",
    "parent_id": 5,
  },
  {
    "area_id": 4,
    "name": "北京市",
    "parent_id": 3,
  },
  {
    "area_id": 3,
    "name": "北京",
    "parent_id": 0,
  },
  {
    "area_id": 2,
    "name": "测试子地区",
    "parent_id": 1,
  },
  {
    "area_id": 1,
    "name": "测试地区",
    "parent_id": 0,
  }
]

emmm,换个念头想想也刚好锻炼锻炼,撸起袖子干吧,然后就总结了以下两种整理方法~

方法一——递归

在这种那么适合递归的场景,怎么能少了递归这个角色呢?第一种方法,递归出场!献上递归宝器~

function toTreeData(data,pid){

  function tree(id) {
    let arr = []
    data.filter(item => {
      return item.parent_id === id;
    }).forEach(item => {
      arr.push({
        area_id: item.area_id,
        label: item.name,
        children: tree(item.area_id)
      })
    })
    return arr
  }
  return tree(pid) // 第一级节点的父id,是null或者0,视情况传入
}

恩,姿势摆好,在控制台里执行一下

哎哟,不错哦~后台小哥哥再也不担心需要返回什么数据给我了。不过,该方法有个缺点,在我使用组件的时候需要的数据结构中,如果子级没有数据children返回[]。恩,有点问题,但是还是可以优化的,优化的代码我会那么容易给出来吗?你已经是个成熟的程序猿了,需要学会自己优化代码了!!!

方法二——对象

对象在我眼里一直是倚天屠龙宝刀的存在,了解到其中的奥妙便形同有一武林秘籍傍身。当然,没用好就相当于一堆废铁,甚至将导致一些不可预料的结果。

function setTreeData(arr) {
  // 删除所有 children,以防止多次调用
  arr.forEach(function (item) {
      delete item.children;
  });
  let map = {}; // 构建map
  arr.forEach(i => {
    map[i.area_id] = i; // 构建以area_id为键 当前数据为值
  });

  let treeData = [];
  arr.forEach(child => {
    const mapItem = map[child.parent_id]; // 判断当前数据的parent_id是否存在map中

    if (mapItem) { // 存在则表示当前数据不是最顶层数据

      // 注意: 这里的map中的数据是引用了arr的它的指向还是arr,当mapItem改变时arr也会改变,踩坑点
      (mapItem.children || ( mapItem.children = [] )).push(child); // 这里判断mapItem中是否存在children, 存在则插入当前数据, 不存在则赋值children为[]然后再插入当前数据
    } else { // 不存在则是组顶层数据
      treeData.push(child);
    }
  });

  return treeData;
};

console.log(setTreeData(data)); // 输出整理后的数据

结果我就不执行了,跟递归的结果相似。相比起递归,我更喜欢这种方法。不过这种方法有一种容易犯错的地方,就是它会改变原数据,我就在这里踩了好久的坑,所以一开始采用了删除children的初始化了一遍。 记住了吗,没记住自行重复说三遍!!!

总结

以上简单介绍了两种将扁平化数据转化为递归树的方法,学会了吗,没学会再回去好好撸撸码!!目前我遇到需要将数据整理树形结构的主要在菜单栏或分类的树形结构上,当然还有像省市这种有从属关系的结构。不过就算以后遇到了都唔驶惊啦~恩,继续更新总结中....

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • JavaScript惰性载入函数实例分析

    本文实例讲述了JavaScript惰性载入函数.分享给大家供大家参考,具体如下: 惰性载入函数 惰性载入函数表示函数执行的分支仅会发生一次,有两种实现惰性载入函数的方式,第一种是在函数被调用时再处理,在第一次调用中,该函数会覆盖为另外一个按合适方式执行的函数,这样任何对函数的调用都不用再经过执行的分支了.第二种实现惰性载入的方式是在声明函数时就制定适当的函数,这样,第一次调用函数时就不会损失性能了,而在代码首次加载时会损失一点儿性能. 载入方式一 var flag = 1; function t

  • JavaScript刷新页面的几种方法总结

    1,reload 方法 该方法强迫浏览器刷新当前页面. 语法:location.reload([bForceGet]) 参数: bForceGet, 可选参数, 默认为 false,从客户端缓存里取当前页.true, 则以 GET 方式,从服务端取最新的页面, 相当于客户端点击 F5("刷新") 2,replace 方法 方法通过指定URL替换当前缓存在历史里(客户端)的项目,因此当使用replace方法之后,你不能通过"前进"和"后退"来访问已

  • 详解javascript函数写法大全

    1.常规写法 function fnName(){ console.log("常规写法"); } 2.匿名函数,函数保存到变量里 var myfn = function(){ console.log("匿名函数,函数保存到变量里"); } 3.如果有多个变量,可以用对象收编变量 3.1 用json对象 var fnobject1={ fn1:function(){ console.log("第一个函数"); }, fn2:function(){

  • javascript验证form表单数据的案例详解

    直接po截图和代码 下面是CheckFormDemo.html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>验证表单的案例</title> <link rel="stylesheet" type="text/css" href="../css/body.css" rel=&q

  • 详解javascript设计模式三:代理模式

    代理模式是一种对程序对象进行控制性访问的一类解决方案. 引入代理模式,其实是为了实现单一职责的面向对象设计原则. 单一职责其实就是指在一个类中(js中通常指对象和函数等),应仅有一个引起它变化的原因.这样会帮助程序设计具有良好的健壮和高内聚特性,从而当变化发生时,程序设计会尽量少的受到意外破坏. 代理模式有多种方法,保护代理.远程代理.虚拟代理.缓存代理等. 但在javascript中,代理模式最常用到的两种方法是虚拟代理和缓存代理. 虚拟代理 在理解虚拟代理时,可以将其想象为一个经纪人,客户程

  • Javascript实现一朵从含苞到绽放的玫瑰

    用javascript实现的一朵从含苞到绽放的玫瑰   代码奉献了!! 偷偷地做成网页发给女朋友,她会高兴的! <html> <head> </head> <body> <canvas id="c"></canvas> <script> var b = document.body; var c = document.getElementsByTagName('canvas')[0]; var a = c

  • Javascript的this详解

    在理解javascript的this之前,首先先了解一下作用域. 作用域分为两种: 1.词法作用域:引擎在当前作用域或者嵌套的子作用域查找具有名称标识符的变量.(引擎如何查找和在哪查找.定义过程发生在代码书写阶段) 2.动态作用域:在运行时被动态确定的作用域. 词法作用域和动态作用域的区别是:词法作用域是在写代码或定义时确定的:动态作用域是在运行时确定的. this的绑定规则 this是在调用时被绑定,取决于函数的调用位置.由此可以知道,一般情况下(非严格模式下),this都会根据函数调用(调用

  • JavaScript偏函数与柯里化实例详解

    本文实例讲述了JavaScript偏函数与柯里化.分享给大家供大家参考,具体如下: 到目前为止我们仅讨论绑定this,现在让我们更深入学习. 我们不仅能绑定this,也可以是参数,这较少使用,但有时很方便. bind完整的语法为: let bound = func.bind(context, arg1, arg2, ...); 可以绑定上下文this和函数的初始参数.举例,我们有个乘法函数mul(a,b): function mul(a, b) { return a * b; } 我们可以在该函

  • JavaScript实现汉字转换为拼音及缩写的方法示例

    本文实例讲述了JavaScript实现汉字转换为拼音及缩写的方法.分享给大家供大家参考,具体如下: 复制代码 代码如下: if(!window.ZXZ){ZXZ={};} ZXZ.widget={}; ZXZ.widget.pinyin = {_pyvalue: ["a", "ai", "an", "ang", "ao", "ba", "bai", "ban

  • JavaScript的级联函数用法简单示例【链式调用】

    本文实例讲述了JavaScript的级联函数用法.分享给大家供大家参考,具体如下: 级联函数 级联函数就是在对象调用中通过点的方式串联调用,在jQuery中就是链式调用, 其关键点就是在内部 return this 返回自身 应用 function Person() { this.name = ''; this.age = 0; this.weight = 10; } Person.prototype = { setName:function(name){ this.name = name; r

随机推荐