函数式编程 -- 函数组合 -- 管道

什么是函数组合?

把细粒度的函数组合成一个新的函数

组合函数有什么用?

假设有一个数组,我们要先翻转数组,再获取数组中的第一个元素,然后把这个元素转化成大写字母

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)
posted @ 2021-06-12 20:16  MissSage  阅读(198)  评论(0编辑  收藏  举报