前沿

前端中设计数据结构的方面不多,最常用的就是对树结构的一些操作。从某种意义上来说,前端工作本身就是和树结构打交道的一个工作方向。毕竟,DOM就是天然的树结构。所以如何能够良好地对树结构进行操作,是前端工程师不可或缺的一项能力。

树结构

定义

什么是树结构呢?从数据结构的角度来讲:

  • 树是非线性数据结构
  • 每个节点可能会有0个或多个后代
  • 每个节点具备唯一的父节点(如果有多个父节点,那就是图了)

分类

树根据节点的不同可以分为不同的类型,最常见的分类是:

  • 二叉树
  • 二叉搜索树
  • 平衡二叉查找树
  • 红黑树 具体他们之间的区别这里就不细说了,具体请查看详情

前端中常见的树结构

DOM树结构

下面的html结构就是一个天然的树结构。每个Dom节点下面,有0/1/多个子节点。

对象树结构

  • 数组形式

特点: 每一个对象节点,下面可能会有children,也可能没有children

let obj = [{id: 1,type: 'dom',children: [{id: 2,type: 'html'}]},{id: 3,type: 'css',children: [{id: 4,type: 'javascript'}]}
];
复制代码
  • 对象形式
    最常见的就是抽象语法树:

特点: 对象的属性下面有不同的属性,每一个属性下面可能还会有不同的属性

这种格式经常在数据统计中出现。

Javascript中树结构的遍历

其实在我看来,树的结构形式有很多种,但是,前端工作中很少涉及对树节点的修改等操作,大部分是遍历和统计数据。

需求场景:下面以Dom树结构为例:
1、需要输出每个节点的名称和节点深度
3、深度优先和广度优先都需要实现

  • 假定已经有了对应的树结构,子节点是childNodes(为啥不用children呢?自己去查吧)

深度优先遍历

深度优先遍历,又叫DFS(deep first search),遍历顺序是优先遍历节点的子节点,然后再是节点的兄弟节点。

  • 递归输出
function DeepSearch(node, deep = 0) {const child = node.childNodes;const { nodeName } = node;console.log(`name:${nodeName},deep:${deep}`);for(let i = 0, len = child.length; i < len; i++) {DeepSearch(child[i], deep + 1);        }
}
复制代码
  • 非递归输出
function deepSearch(node, deep = 0) {const stack = [];const deepArr = [];stack.push(node);deepArr.push(0);while(stack.length !== 0){const node = stack.shift();const deep = deepArr.shift();const { nodeName } = node;console.log(`name:${nodeName},deep:${deep}`);const nodes = child.childNodes;for( let i = node.length; i > 0; i--) {stack.unshift(nodes[i]);deep.unshift(deep + 1);}}
}
复制代码

广度优先遍历

广度优先,正好和深度优先策略相反,先遍历节点的兄弟节点,再遍历子节点。

  • 递归输出
function BreadSearch(node, deep = 0) {const child = node.childNodes;const res = [];for(let i = 0, len = child.length; i < len; i++) {const { nodeName } = node;console.log(`name:${nodeName},deep:${deep}`);res.push(child[i]);}DeepSearch(res, deep + 1);        }
复制代码
  • 非递归输出
function breadSearch(node, deep = 0) {const stack = [];const deepArr = [];stack.push(node);deepArr.push(0);while (stack.length !== 0 ) {const node = stack.shift();cosnt deep = stack.shift();const { nodeName } = node;console.log(`name:${nodeName},deep:${deep}`);for(let i = 0, len = child.length; i < len; i++) {stack.push(child[i]);}}
}
复制代码

业务场景

前端中的树操作,经常是生成特定的树结构。常见的场景有生成路由和生成菜单。

路由

下面以react-router为例,说明:

简单情况(bad)

一般情况下,react-router的路由是下面的:

<Switch><Route path="/home" component={A}/><Route path="/manage" component={B}/><Route path="/customer" component={C}/>... ...
</Switch>
复制代码

但是如果所有的都按照上面的写法,每加一个路由,都需要取在内容下面,加一个

    <Route path="/extra" component={D}/>
复制代码

这样会造成代码不容易维护,而且可读性不好

配置的方式(better)

配置的方式总好过,每次打开路由的内部代码修改。

const routers = [{path: '/a',component: A},{title: '考试',id: 'exam',path: '/b',children: [{path: '/c',component: C},{path: '/d',component: D}]}
];function getRoute (routes, rootPath = '') {let res = [];for (let i = 0, len = routes.length; i < len; i++) {const route = routes[i];const { path } = route;if (route.children) {res = [...res, ...getRoute(route.children, path)];} else {res.push(<Routepath={`${rootPath}${path}`}...route/>);}}return res;
};<Switch>{getRoute(routers)}
</Switch>
复制代码

菜单

菜单和路由的方式很相似,而且通常会结合在一起使用,具体的写法,这里就不赘述了,因为实在是太相似了,留给你们吧。。

参考资料

转载于:https://juejin.im/post/5d064d31e51d455071250b04

Javascript中的树结构相关推荐

  1. 12.在JavaScript中的事件模型如何理解?

    一.事件与事件流 javascript中的事件,可以理解就是在HTML文档或者浏览器中发生的一种交互操作,使得网页具备互动性, 常见的有加载事件.鼠标事件.自定义事件等 由于DOM是一个树结构,如果在 ...

  2. 前端技术学习第四讲:JavaScript中DOM和BOM

    JavaScript中DOM和BOM 一.DOM和BOM DOM:文档对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展置标语言的标准编程接口.它是一种与 ...

  3. 浅析 JavaScript 中的 函数 uncurrying 反柯里化

    柯里化 柯里化又称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果. 因此柯里化的过程是 ...

  4. JavaScript中,this的绑定规则

    对于 JavaScript 新手来说,this 是非常基础同时也难以理解的知识点. 比如下面的代码,this 指向就有三种方式. 在<你不知道的 JavaScript>一书中,我总算比较清 ...

  5. Javascript中undefined,NaN等特殊比较

    以下内容转自: http://blog.csdn.net/hongweigg/article/details/38090093 1.问题:在Javascript中,typeof(undefined) ...

  6. Javascript中二进制数据处理方法

    Javascript中二进制数据处理方法 转载于:https://www.cnblogs.com/motadou/archive/2012/02/19/2358514.html

  7. JavaScript 中的有限状态机

    http://www.ibm.com/developerworks/cn/web/wa-finitemach/ JavaScript 中的有限状态机 Page navigation 系列文章 有限状态 ...

  8. 在Javascript中使用面向对象的编程

    by Mike Koss March 26th, 2003 这是一篇,我个人认为最好的,Javascript面向对象编程的文章.翻译不好的地方,还望大家指正,谢谢. 如果您需要,可以访问下面的地址取得 ...

  9. 取出url中的字符_如何在JavaScript中解析URL:例如主机名,路径名,查询,哈希?...

    统一资源定位符(缩写URL)是对Web资源(网页,图像,文件)的引用.URL指定资源位置和检索资源的机制(http,ftp,mailto). 例如,这是此博客文章的URL: 通常,您需要访问URL的特 ...

最新文章

  1. IBM全面拥抱Linux,为“认知商业”提供POWER
  2. 谈谈Spanner和F1
  3. python学生管理系统-学生管理系统python
  4. DataTable 转 Entity
  5. 今天突然想到一个问题:地球在转动吗,由东西向西跳与由西向东跳哪个更远...
  6. cross product
  7. HarmonyOS之JS/Java跨语言调试
  8. angular 数字逗号分隔_angular 实现的输入框数字千分位及保留几位小数点功能示例...
  9. 接受的token无法改变_基于BCH的新Token方案SLP的原理与应用
  10. Django-ModelFrom中修改save后的字段值
  11. java反射创建实例_Java反射创建实例
  12. jms 教程_JMS教程–什么是JMS
  13. WPF学习笔记——4)使用StackPanel面板进行简单布局
  14. 通过身份证号码提取年龄,性别
  15. 学习报告:基于原型网络的小样本学习《Prototypical Networks for Few-shot Learning》
  16. 莫以物喜 、莫以己悲!
  17. 【Maxent物种分布模型】气候变化对响尾蛇地理分布的影响
  18. Linux系统和Windows系统的区别
  19. idea maven打包war包项目
  20. 祁隆乐凡短视频隔空宣战,和合国际收购祁隆歌曲《借我星光》版权

热门文章

  1. 「镁客·请讲」仙知机器人赵越:“能友好工作”的机器人才能真正的为人类服务...
  2. ORACLE的直方图的一些试验
  3. 我的WCF之旅(6):在Winform Application中调用Duplex Service出现TimeoutException的原因和解决方案...
  4. canvas知识点总结2
  5. 算法竞赛入门经典系列
  6. linue 查询端口号 netstat
  7. 继续着茫茫碌碌的日子
  8. PHP大数组过滤元素、修改元素性能分析
  9. 教你用Python爬取图虫网
  10. ServerSocket01