JS函数式编程和递归探索:路由树的操作

JavaScript034

JS函数式编程和递归探索:路由树的操作,第1张

开始切入正题之前,有必要告知大家一下,这篇文章可能有一些深度,初学者可能理解会有些吃力。我会尽量把复杂问题简单化,争取让每个阅读的童鞋们都能看得懂。希望你对element-ui,vue-router,KeepAlive组件有一点了解。现在,我们开始吧。

熟悉element-ui的童鞋们都知道,ElMenuItem和ElSubMenu都需要一个index属性,该属性必须是唯一的。现在,我们想把路由配置直接应用于ElMenu,该如何确保index的唯一性呢?我们需要有一个生成唯一index的函数。如下是genKey函数的定义,是不是很简单?

现在,我们创建addRouteMetaKey函数,该函数对路由树进行递归遍历,为每一个路由配置的meta属性动态添加key字段。这个函数很简单,属于最基础的递归使用例子,我就不做太多解释了。

提示 :数组的forEach方法不是纯函数,因为它有副作用,所以forEach方法不能称之为函数式编程工具。

通过addRouteMetaKey函数,我们可以把路由的meta.key作为index的值了。

现在,我们想实现另一个功能,就是 基于标签页的路由组件缓存控制 。使用过Vuejs KeepAlive组件的童鞋们,应该多多少少都遇到一些坑吧?在我们的项目中,有一个顶部标签页导航,每个tab项对应一个url,以每个url对应路由的title作为tab项标题,当切换tab的时候加载缓存中的url对应的路由组件,关闭tab项,下次打开该路由url,重新挂载对应的路由组件,而不是从缓存中加载。

当路由层级不确定的时候,KeepAlive会变的难以手动控制。所以,我 剑走偏锋,尝试了一种简单的解决方案 ,实践证明: 这是非常有效的 。我的方案就是把无限层级的路由树转化为一维数组。通过为meta添加必要的字段,进行页面结构个性化定制。

我们需要把每层路由配置的path转化为全路径,所以需要一个函数:getRouteFullPath,该函数定义如下:

getRouteFullPath函数中使用到的joinPath函数用于将多个路径字符串拼接为1个完整的路径,定义如下:

现在,我们把路由树转化为一维数组。我们定义toFlatRoutes函数,该函数使用了数组的reduce方法对路由树进行聚合递归,将路由配置中的path属性的值替换为全路径,还顺便给路由配置添加了name属性,返回一个新的一维路由配置数组。 这是函数式编程和递归结合的一个例子。

以上,我们解决了KeepAlive的缓存控制问题;现在,我们又有了一个新的用户体验上的需求,就是我们想根据url对应的路由,自动展开该路由meta.key所属的侧边菜单;我们通过查阅element-ui文档得知,ElMenu有一个open方法,接收index作为参数,展开index对应的菜单。

现在的问题是,我们的路由对应的index是ElMenuItem的,而路由树已经被我们转化为了一维数组,通过路由的matched字段是得不到我们想要的菜单index的。所以, 我们需要遍历原始路由树

如下代码,我们定义getMenuKey函数,该函数接收的参数为route对象。如果路由存在,我们进行查找。首先进行简单查找,如果找到一个菜单menu,则返回该菜单的meta.key;如果简单查找无果,则对路由树进行递归查找; 这是函数式编程和递归结合的另一个例子。

现在,我们大功告成了;以上就是本节的知识点,童鞋们理解了吗?只要我们熟悉递归的使用,其实操作树很简单。如果大家还有不懂的,可以评论区问我。感谢阅读!

immutable,副作用,纯函数关键词解释:

js 中的对象一般是可变的,因为使用了引用赋值,虽然可以节约内存,但是会有一些隐患。一般做法使用浅拷贝和深拷贝来避免修改,但是这样会造成 CPU 和内存浪费。

为了解决这个问题,出现了 immutable.js 和 immer

immutable.js 实现原理: Persistent Data Structure (持久化数据结构)。

内部实现了一套 Persistent Data Structure,还有很多易用的数据类型像 Collection 、 List 、 Map 、 Set 、 Record 、 Seq 。有非常全面的 map 、 filter 、 groupBy 、 reduce``find 函数式操作方法。同时 API 也尽量与 Object 或 Array 类似。

缺点:

和 redux 的配合使用,redux 简化了 Flux 中多个 store 的概念,只有一个 store,数据操作通过 reducer 使用。reducer 就是要接受一个纯函数。

mobx 作者写的一个 immutable 库,核心实现利用 es6 的 proxy。

immer 使用原生数据结构的 api,而不像 immutable-js 转化为内置对象的 api。

学习成本低,就是把之前的操作放置到 produce 函数的第二参数函数中去执行。

原理:使用了一个 ES6 的新特性 Proxy 对象。深层嵌套对象的结构化共享的处理

proxy 具体可以看 Proxy

Proxy 无法 polyfill,所以 immer 在不支持 Proxy 的环境中,使用 Object.defineProperty 来进行一个兼容。

immer 维护一份 state 在内部,劫持所有操作,内部来判断是否有变化从而最终决定如何返回。

函数式编程:

知道如何使用纯函数进行声明式编程是一个人应该具备的另一种关键技能,因为它可以完全改变你的编码方式,变得更好。使用函数式编程,您可以纯粹通过函数编写代码,避免共享状态、数据突变和副作用。由于函数式编程的声明性质,生成的代码更简洁、可预测并且更易于测试和更改。此外,由于它简洁,可以更快地执行代码,从而缩短加载时间。学习函数式编程可能既困难又耗时,但它所带来的优势使其值得花时间。

编写跨浏览器代码:

一般来说,互联网用户不会坚持只使用一个网络浏览器;有些人可能更喜欢使用Internet Explorer,而其他人可能更喜欢使用 Google Chrome。在这种情况下,您无法编写在单个 Web 浏览器上运行的代码,因为这会严重限制您的网站受众并阻碍您网站的增长潜力

为了确保您的网站可以在流行的浏览器、移动设备和任何其他网络浏览设备上使用,编写与多个网络浏览器兼容的 JavaScript 代码至关重要。

高效的内存管理:

编写内存高效的 JavaScript 代码的能力是一项随着时间的推移而发展起来的技能,但您仍然应该知道这一技能。任何 Web 应用程序或网站都可能泄露内存,如果代码不适合内存优化,则会导致速度变慢。内存泄漏有时甚至会导致大量性能问题,因为它们最终会消耗大量宝贵的系统资源。尽管 JavaScript 有自己的自动内