怎么在JavaScript中实现一个数组惰性求值库
今天就跟大家聊聊有关怎么在JavaScript中实现一个数组惰性求值库,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。
javascript是一种什么语言
javascript是一种动态类型、弱类型的语言,基于对象和事件驱动并具有相对安全性并广泛用于客户端网页开发的脚本语言,同时也是一种广泛用于客户端Web开发的脚本语言。它主要用来给HTML网页添加动态功能,现在JavaScript也可被用于网络服务器,如Node.js。
惰性求值每次求值的时候并不是返回数值,而是返回一个包含计算参数的求值函数,每次到了要使用值得时候,才会进行计算。
当有多个惰性操作的时候,构成一个求值函数链,每次求值的时候,每个求值函数都向上一个求值函数求值,返回一个值。最后当计算函数终止的时候,返回一个终止值。
具体实现
判断求值函数终止
每次求值函数都会返回各种数据,所以得使用一个独一无二的值来作为判断流是否完成的标志。刚好 Symbol() 可以创建一个新的 symbol ,它的值与其它任何值皆不相等。
const over = Symbol();const isOver = function (_over) { return _over === over;}
生成函数 range
range 函数接受一个起始和终止参数,返回一个求值函数,运行求值函数返回一个值,终止的时候返回终止值。
const range = function (from, to) { let i = from; return function () { if (i < to) { i++ console.log('range\t', i); return i } return over; }}
转换函数 map
接受一个求值函数和处理函数,获取求值函数 flow 中的数据,对数据进行处理,返回一个流。
const map = function (flow, transform) { return function () { const data = flow(); console.log('map\t', data); return isOver(data) ? data : transform(data); }}
过滤函数 filter
接受一个求值函数,对求值函数 flow 中数据进行过滤,找到符合的数据并且返回。
const filter = function (flow, condition) { return function () { while(true) { const data = flow(); if (isOver(data)) { return data; } if(condition(data)) { console.log('filter\t', data); return data; } } }}
中断函数 stop
接受一个求值函数,当达到某个条件时中断,可以用闭包函数加上 stop 函数接着实现一个 take 函数。
const stop = function (flow, condition) { let _stop = false; return function () { if (_stop) return over; const data = flow(); if (isOver(data)) { return data; } _stop = condition(data); return data; }}const take = function(flow, num) { let i = 0; return stop(flow, (data) => { return ++i >= num; });}
收集函数 join
因为返回的都是一个函数,最后得使用一个 join 函数来收集所有的值并且返回一个数组。
const join = function (flow) { const array = []; while(true) { const data = flow(); if (isOver(data)) { break; } array.push(data); } return array;}
测试:
const nums = join(take(filter(map(range(0, 20), n => n * 10), n => n % 3 === 0), 2));console.log(nums);
输出:
range 1
map 1
range 2
map 2
range 3
map 3
filter 30
range 4
map 4
range 5
map 5
range 6
map 6
filter 60
更优雅的实现
上面使用 函数 + 闭包 实现了惰性求值,但是还是不够优雅,绝大部分代码都放到迭代和判断求值是否完成上面去了。其实 es6 中还有更好方法来实现惰性求值,就是使用 generator,generator 已经帮我们解决了迭代和判断流是否完成,我们就可以专注于逻辑,写出更简洁易懂结构清晰的代码。
const range = function* (from, to) { for(let i = from; i < to; i++) { console.log('range\t', i); yield i; }}const map = function* (flow, transform) { for(const data of flow) { console.log('map\t', data); yield(transform(data)); }}const filter = function* (flow, condition) { for(const data of flow) { console.log('filter\t', data); if (condition(data)) { yield data; } }}const stop = function*(flow, condition) { for(const data of flow) { yield data; if (condition(data)) { break; } }}const take = function (flow, number) { let count = 0; const _filter = function (data) { count ++ return count >= number; } return stop(flow, _filter);}
还得加上链式调用才算是完成了。
class _Lazy{ constructor() { this.iterator = null; } range(...args) { this.iterator = range(...args); return this; } map(...args) { this.iterator = map(this.iterator, ...args); return this; } filter(...args) { this.iterator = filter(this.iterator, ...args); return this; } take(...args) { this.iterator = take(this.iterator, ...args); return this; } [Symbol.iterator]() { return this.iterator; }}function lazy () { return new _Lazy();}
最后再测试一下:
const nums = lazy().range(0, 100).map(n => n * 10).filter(n => n % 3 === 0).take(2);for(let n of nums) { console.log('num:\t', n, '\n');}
输出:
range 0
map 0
filter 0
num: 0
range 1
map 1
filter 10
range 2
map 2
filter 20
range 3
map 3
filter 30
num: 30
看完上述内容,你们对怎么在JavaScript中实现一个数组惰性求值库有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注编程网行业资讯频道,感谢大家的支持。
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341