JS 函数式编程案例
2021/7/15 14:08:49
本文主要是介绍JS 函数式编程案例,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
前言
最近遇到一个应用场景,用于检测页面是否加载过带有某个特征的 URL。实现原本很简单:
var entries = performance.getEntriesByType('resource') var ret = entries.some(function(v) { return /xxx/.test(v.name) })
但由于某些原因,要求代码中不能出现 function
关键字。(箭头函数不用考虑,语法兼容性就不行。至于 eval
之类的动态执行那就更不用提了)
也就是说,即使要有回调,函数也只能通过 JS 或 DOM 内置的 API 创建。
下面开始挑战。
简单但低效的方案
最先想到的方案非常简单,根本不用函数。直接将 entries
数组序列化成字符串,一步到位:
var str = JSON.stringify(entries) var ret = /xxx/.test(str)
不过该方案存在性能问题。由于 Performance API 记录了大量信息,导致序列化的开销非常大。
例如淘宝首页,打开后往下翻几页,URL 记录多达数百条,序列化用时数毫秒,字符串长度超过十万。
函数式编程
回到主题,我们尝试用 JS 或 DOM 内置的 API 创建回调函数。
回顾本文开头的代码:
var entries = performance.getEntriesByType('resource') var ret = entries.some(function(v) { return /xxx/.test(v.name) // 如何用 JS 内置的方法实现这个逻辑? })
回调函数中的逻辑看似简单,但实际上做了两件事:读取 name
属性、调用 test
方法。
为了方便理解,我们将这两件事进行拆分,每次只做一件。
1.读取属性
我们将 entries
数组转换成 urls
字符串数组,类似如下逻辑:
var urls = entries.map(function(v) { return v.name })
2.调用方法
在 urls
数组中搜索关键字,类似如下逻辑:
var ret = urls.some(function(v) { return /xxx/.test(v) })
下面开始逐一突破。
属性读取函数化
若想通过函数调用的方式读取属性,显然需要用到 读访问器
,即 getter
。
Performance API 记录中的 name
属性定义于 PerformanceEntry
类,因此可通过如下方式获取该属性的 getter
:
var nameGetter = Object.getOwnPropertyDescriptor(PerformanceEntry.prototype, 'name').get
现在读取属性,即可抛弃 entries[n].name
的形式,换成函数调用的形式:
nameGetter.call(entries[n]) // "https://..."
是不是有种倒装句的感觉?
我们把谓语放在最前,主语放在最后。因为我们强调的是读属性这个行为,而不是强调读谁的。这个「谁」,可以指代数组中任何一个元素。
现在,我们代码变成了这样:
// 临时版 var urls = entries.map(function(v) { return nameGetter.call(v) })
显然,如果能直接将 nameGetter.call
传给 map
回调,那么 function
就可以去掉了。
// 这样可以吗?好像缺了什么。。。 var urls = entries.map(nameGetter.call)
因为 nameGetter.call
只是 Function.prototype.call
的一个引用,是不带上下文的。
nameGetter.call === Function.prototype.call // true
好在数组的 map
方法还有 第二个参数,用于设定回调函数的 this
上下文。
于是,我们可以把 nameGetter
作为 map
的第二个参数:
// 大功告成 var urls = entries.map(nameGetter.call, nameGetter)
成功得到所有记录的 URL 数组!
调用方法
事实上,数组的迭代方法都支持设置 this 上下文。
因此,我们使用同样的思路,实现字符串数组的正则搜索。例如:
var reg = /google/ urls.find(reg.test, reg) // "https://www.google.com/..."
或者使用 some
方法,直接判断是否存在。
完整实现
var nameGetter = Object.getOwnPropertyDescriptor(PerformanceEntry.prototype, 'name').get var entries = performance.getEntriesByType('resource') var urls = entries.map(nameGetter.call, nameGetter) var reg = /xxx/ urls.some(reg.test, reg)
实现很简单,性能也很高,并且没有出现任何一个字面函数。
这篇关于JS 函数式编程案例的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-21Vue3教程:新手入门到实践应用
- 2024-12-21VueRouter4教程:从入门到实践
- 2024-12-20Vue3项目实战:从入门到上手
- 2024-12-20Vue3项目实战:新手入门教程
- 2024-12-20VueRouter4项目实战:新手入门教程
- 2024-12-20如何实现JDBC和jsp的关系?-icode9专业技术文章分享
- 2024-12-20Vue项目中实现TagsView标签栏导航的简单教程
- 2024-12-20Vue3入门教程:从零开始搭建你的第一个Vue3项目
- 2024-12-20从零开始学习vueRouter4:基础教程
- 2024-12-20Vuex4课程:新手入门到上手实战全攻略