函数式编程 -- 函数组合 -- 管道
什么是函数组合?
把细粒度的函数组合成一个新的函数
组合函数有什么用?
假设有一个数组,我们要先翻转数组,再获取数组中的第一个元素,然后把这个元素转化成大写字母
var arr=["a","b","c"]
var upperChar = toUpper(getFirstChar(reverseArray(arr)))
可能我们的代码写完后是上面这样的,就像洋葱一样,一层一层的,当我们需要增加或者 减少逻辑时,修改代码稍显麻烦,其实我们可以把这些函数组合起来,这样修改业务逻辑时,只需要修改传入组合函数的参数就行了
函数组合
-
如果一个函数需要经多个函数处理才能得到最终值,这个时候可以把中间过程的函数组合成一个函数
- 函数就像数据的管道,函数组合就是把这些管道连接起来,让数据穿过多个管道形成最终结果
- 函数组合默认是从右向左执行的
-
案例演示
// 函数组合演示,获取数组最后一个元素 // 组合函数 function compose(f,g){ return function(value){ retturn f(g(value)) } } // 数组翻转函数 function reverse(array){ retutrn array.reverse() } // 获取数组第一个元素 function first(array){ return array[0] } // last是组合后的函数,集合了reverse方法和first方法,作用是取得数组的最后一个元素 const last=compose(first,reverse) console.log(last([1,2,3,4]))
-
这里只是讲的函数组合与管道的思想,目的就是想说函数可以任意的组合和调用,函数式编程可以让函数最大程度的被重用
lodash中的函数组合
// lodash 中的函数组合方法:_.flowRight(),此方法可以接收任意多个需要组合的函数作为参数
const _ = require('lodash')
// 用于组合的reverse方法,作用是翻转数组
const reverse = arr =>arr.reverse()
// 用于组合的first方法,作用是取数组的第一个元素
const first = arr => arr[0]
// 用于组合的toUpper方法,作用是把字符串转换成大写
const toUpper = s = >s.toUpperCase()
// 组合函数flowRight的执行是从右向左
// 先执行reverse将数组翻转
// 再执first取数组的第一个元素
// 最后执行toUpper将取得的元素转换成大写
const f = _.flowRight(toUpper,first,reverse)
console.log(f(['one','two','three']))
模拟一下lodash的flowRight方法
function myFlowRight(...args){
return function(value){
return args.reverse().reduce(function(acc,fn){
return fn(acc)
},value)
}
}
//上面myFlowRight用箭头函数重写如下:
const myFlowRight=(...args)=>value=>args.reverse().reduce((acc,fn)=>fn(acc),value)
// 测试一下
const reverse = arr =>arr.reverse()
const first = arr => arr[0]
const toUpper = s = >s.toUpperCase()
const f = myFlowRight(toUpper,first,reverse)
console.log(f(['one','two','three']))
函数组合的结合律
因为函数组合后返回的还是一个函数,所以函数组合是满足结合律的
像下面一样,可以把f、g组合,也可以把g、h组合,结果都是一样的
// 结合律
let f = compose(f,g,h)
let associative = compose(compose(f,g),h) == compose(f,compose(g,h))
管道
- 下面这张图表示程序中使用函数处理数据的过程,给fn函数输入参数a,返回结果b,中间的处理过程我们称之为数据处理管道
-
当fn比较复杂时,我们可以把函数fn拆分成多个小函数,此时多了两个运算过程中产生的m、n
-
下面这张图中可以想象成把fn这个管理折成了3个管道f1,f2,f3,数据a通过管道f3得到结果m,m再通过f2得到n,n最后通过f1得到b
用代码表示如下:
var fn = compose(f1,f2,f3)
b=fn(a)