pipe函数与compose函数

pipe函数与compose函数 转眼间自己写代码已经两年了,这期间从刚开始的什么都不会,到会写一些页面,在到可以熟练的写一些业务代码。几乎每天都是拼凑,对于小的项目已经简单的业务来说没什么问题,但随着时间的流逝,业务变得越来越复杂,代码体积越来越庞大,随之而来的bug也就越多。
出于一个程序员的本能,开始对软件架构有一些思想,并开始学习。
最近有接触到两个函数一个是pipe函数一个compose函数,下面来分享一下
什么是compse函数 compose函数就是,就是可以把一些函数串联起来,第一个函数返回值作为后一个函数的参数,依次执行。
在我们编码的过程中,我们可以将复杂的逻辑拆解为简单的运算单元。然后通过这些运算的单元的拼凑,可以实现复杂的运算。从而做到,每一个运算单元可以有单一职责,单元跟单元之间互相没有关系。对于整体运算更加具有语义化。
举个例子

/** * 实现一个函数,计算x * 2 / 3 + 4 - 5的结果 */// 我们普通是想法function cal(x) { return typeof x === 'number' ? x * 2 / 3 + 4 - 5 :x }

首先, 上面的写法是没有问题的,可以实现我们的需求。
但是,这种代码是比较典型命令式编程,可扩展性与可复用性更差。
下面我们对他进行拆分实现可以函数有更好的可复用性
// 为了提高代码的复用性我们进行拆分 // 首先我们来定义我们的基本运算 function add(n) { return n + 4 }function sub(n) { return n - 5 }function mul(n) { return n * 2 }function division(n) { return n / 3 }// 最终的函数, 大功告成 function cal(x) { return sub(add(division(mul(x)))) }

上面的方法看起来确实,把之前的运算逻辑做了一些拆分,但是最终我们得到的函数,仍然显得比较丑陋,特别是当面对很长的函数命名时,胃里顿时翻江倒海。
用JavaScript来实现一个compose函数 【pipe函数与compose函数】话不多说直接代码
// 首先compose函数 function compose(a, b, c, d) { return function(x) { return d(b(c(a(x)))) } }// 此处省略我们定义的基本运算函数// 然后我们使用compose函数来实现我们的需求 var cal = compse(mul, division, add, sub)

很不错!看起来好了许多,并且我们通过改变我们传入compse函数的顺序进行不同的运算。
但是,这个我们只能吧运算单元拆分为四个,如果不然就需要写接收更多参数的compse。太坑了!
使用reduce函数 在这里要推出一个重量级选手reduce函数
下面是来自mdn的解释,详细可以查看MDN关于reduce的详细解释
**reduce()** 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。
与之相关的有一个函数reduceRight,执行的方向与reduce刚好想反。具体reduce的用法这里不做多余解释。
兼容性大家可以上caniuse查看,它在新的浏览器上有很好的支持。
下面是使用reduce韩式实现的compse。
function compse() { // 首先获取参数 var args = [].slice.call(arguments) // reduceRight从右往左 return args.reduceRight(function(a, b) { return function(x) { return a(b(val)) } }) }var cal= compse(mul, division, add, sub)

这样好了,我们的compose接收的参数数量就不会受限制了,这样的compse函数用途更为广泛。
下面我们使用es6语法实现一遍
const compose = (...args) => { return x => args.reduceRight((a, b) => x => a(b(x))) }

对于pipe函数只是计算的顺序刚好相反, 我们将compse函数中的reduceRight替换为reduce即可
代码如下:
const pipe = (...args) => { return x => args.reduce((a, b) => x => a(b(x))) }

最后大功告成!谢谢

    推荐阅读