组合与管道

1.9k words

作用:保证每个函数的低粒度,只关注于某一件事。除了方便测试外,还可以通过组合来构建出一个新的函数。此时该组合出的新函数具有多项功能(粗粒度的函数)

🌰 例如

产生一个随机整数

🍐 正常使用

1
2
3
4
5
6
/* 产生随机数,带小数 */
const random = (n) => Math.random() * n
/** 去除小数整化为整数 */
const toInt = (n) => parseInt(n, 10)
// 产生 100之内的整数
const n = toInt(random(100))

💡 使用组合

1
2
3
4
5
6
7
8
9
/** 简单的 compose 方法,接受两个方法从右至左执行 */
const compose = (fnLeft, fnRight) => {
return (val) => fnLeft(fnRight(val))
}

// 使用 compose 组合成一个新的方法,产生随机的整数
const randomInt = compose(toInt, random)
// 产生 100之内的整数
console.log(randomInt(100))

tips: 观察 compose 可知,组成出来的新函数是一元函数, 如果需要组合多元函数. 可使用 柯里化 | 偏函数

🎵 结合律

组合的优势在于:函数组合总是满足结合律

1
2
// 伪代码 二者执行后的结果是完全等价的
compose(compose(f, g), h) === compose(f, compose(g, h))

🌰 结合律例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* 按空格切割单词 */
const splitIntoSpaces = (str) => str.split(' ')
/** 统计单词数量 */
const countWord = (arr) => arr.length
/** 判断单词数量为奇数还是偶数 */
const oddOrEven = (n) => (n % 2 === 0 ? 'even' : 'odd')

// 根据结合律,fn1与fn2执行结果是完全等价
const fn1 = compose(oddOrEven, compose(countWord, splitIntoSpaces))
const fn2 = compose(compose(oddOrEven, countWord), splitIntoSpaces)

// 执行
const str = 'this is your computer'
console.log(fn1(str)) // even
console.log(fn2(str)) // even

基于以上的特性,开发者可以放心大胆的组合函数。如果需要添加新的功能属性,仅需要再 compose 组合一遍,例如想在函数执行时添加一个打印调试

1
2
3
4
5
// 添加打印
const fn3 = compose(fn2, (it) => {
console.log(it)
return it
})

以上就是 compose 的运行机制,数据流是从右往左(顺序不可变)。还有另外一种数据流的方式从左往右,即管道 pipeline或称序列 sequence

🦌 管道

pipe 单纯是 compose 的复制品,仅仅是改变了数据流的方向

🍐 定义pipe

1
2
3
const pipe = (fnLeft, fnRight) => {
return (val) => fnRight(fnLeft(val))
}

tips: pipe具有compose一样的功能和特性, 二者是等价的。但在程序开发中最好指定其中一种方式,避免数据混乱

💡 | 管道符

unix 系统中,可以使用管道符 | 将结果输入到下一个指令中

1
2
# cat 01.txt 输入文本 => grep 从结果中查询 world 字符
cat 01.txt | grep "world"

🍐 Point Free

将一些对象自带的方法转化为纯函数,不要转瞬即逝的中间变量

1
2
3
4
5
6
7
8
// 🙅🏻‍♀️ 转瞬即逝的变量 `toUpperCase()`
const splitSpaceWord = (str) => str.toUpperCase().split(' ')

// Point Free式做法
const splitSpace = str.split(' ')
const toUpperCase = str.toUpperCase()
/** 使用组合成一个新的函数 */
const splitSpaceWord2 = compose(splitSpace, toUpperCase)