函数组合多用于纯函数,为什么?因为纯函数说白了就是入参固定,返回值固定的函数。可预测、可控制。如果不可控还有什么组合的意义?
函数组合就是 一个纯函数套一个纯函数如:
const f1 = () => console.log('f1')
const f2 = () => console.log('f2')
const f3 = () => console.log('f3')
// 组合:
f1(f2(f3()))
如果知道有哪些函数还好,按照上面的写法直接套娃也不是不行,但是有些业务场景我们不确定会有多少个函数要套娃,这就需要组合函数了。
我们需要这么一个函数:
1,有一个函数fn,
2,它的参数是由不确定个数的函数组成
3,最后返回一个函数作为套娃的入口
4,返回的这个函数内部实现套娃
// 1、fn函数
function fn () {}
// 2 它的参数是由不确定个数的函数组成
function fn (...args) {}
// 3,最后返回一个函数作为套娃的入口
function fn (...args) {
return function() {}
}
// 4,返回的这个函数内部实现套娃
function fn (...fns) {
return function() {
let res;
fns.forEach(f => {
res = f(res)
})
}
}
循环执行传入的函数就行, 比如fns = [f1, f2, f3], 那么执行第一次过程就是 res = f1(res),把结果赋值给res; 执行第二次就是f2(res),此时res是第一次的结果,相当于f2(f1(res)); 同样f2的结果赋值给res; 接下来第三次 f3(res) 相当于f3(f2(f1(res)));这样子是不是就是可以无限套娃了?
好了,现在为了让函数更加语义化一些改名为compose
// 4,返回的这个函数内部实现套娃
function compose (...fns) {
return function() {
let res;
fns.forEach(f => {
res = f(res)
})
}
}
再为了一开始第一个函数就可以传参数,再调整一下, 传入参数: arg, 与及 最后一个函数执行完之后能返回结果,把res返回
// 4,返回的这个函数内部实现套娃
function compose (...fns) {
return function(arg) {
let res = arg
fns.forEach(f => {
res = f(res)
})
return res
}
}
试一下效果
function compose (...fns) {
return function(arg) {
let res = arg
fns.forEach(f => {
res = f(res)
})
return res
}
}
const f1 = n => {console.log('f1:', n); return ++n}
const f2 = n => {console.log('f2:', n); return ++n}
const f3 = n => {console.log('f3:', n); return ++n}
const composeFn = compose(f1, f2, f3)
const res = composeFn (1)
console.log('最后的结果是:', res)
结果预期是打印是
f1: 1
f2: 2
f3: 3
最后的结果是:4
如图确实如此
最后认真看着上面的方法,发现还能简洁点,分析发现,函数一开始把参数arg赋值给res, 然后 fns循环执行每个函数,每个函数的参数都是上一个循环执行函数的结果,循环结束把最后结果返回出去。仔细想想,这不就是reduce的用法吗?
改造一下,把arg作为初始值,放到reduce第三个参数,每次循环执行的结果返回出去给下一轮循环。
function compose (...fns) {
return function(arg) {
return fns.reduce((res, f) => {
return f(res)
},arg)
}
}
再变简洁点,通过箭头函数, 把这三个return 去掉。
const compose = (...fns) => arg => fns.reduce((res, fn) => fn(res), arg)
再简洁点,让别人一眼看不懂,变量改成abcde, 达到装比效果。
const compose = (...a) => b => a.reduce((d, e) => e(d), b)
再来一把验证:
composeFn.png
恭喜我自己,装比成功。
网友评论