compose
compose 是函数式编程中一个非常重要的函数,compose 的函数作用就是组合函数的,将函数串联起来执行。将多个函数组合起来,一个函数的输出结果是另一个函数的输入参数,一旦第一个函数开始执行,就会像多米诺骨牌一样推导执行了。
2.1 简单例子
比如有这样的需求,输入一个名字
yideng
,然后全部变成大写,打印输出HELLO YIDENG
,我们可以考虑用函数组合的方法来解决这个问题,需要两个函数greeting、toUpper
。const greeting = (name) => `hello ${name}`; const toUpper = (str) => str.toUpperCase(); const fn = compose(toUpper, greeting); console.log(fn("yideng")); // HELLO YIDENG
这就是 compose 的大致使用,主要有以下几点:
- compose 参数是函数,返回也是一个函数
- 除了第一个函数接受参数,其它函数接受的都是上一个函数的返回值,所以初始函数的参数是多元的,而其它函数的接受值是一元的。
- compose 函数可以接受任意的参数,所有的参数都是函数,且执行方向是自右向左的,初始函数一定放到参数的最右面。
知道这几点之后,上边的 compose 执行过程就很容易分析出来了,执行
fn('yideng')
的时候,初始函数为 greeting,执行结果作为参数传递给 toUpper,再执行 toUpper,得出最后的结果。compose 的好处就是如果再想加一个处理函数,不需要修改 fn,再执行一个 compose 就可以了。比如再加一个 trim。
const trim = (str) => str.trim(); const newFn = compose(trim, fn); console.log(newFn("yideng"));
2.2 参考实现
- 简单实现:递归实现
const compose = function (...funcs) { let len = funcs.length, count = len - 1, result = null; // 首先compse 返回的是一个函数 return function fn(...args) { // 函数体里就是不断执行args函数,将上一个函数的执行结果作为下一个执行函数的输入参数,需要一个count来记录args函数列表的执行情况 result = funcs[count].apply(this, args); // 递归退出条件 if (count <= 0) { count = len - 1; return result; } else { count--; return fn.call(null, result); } }; }; // 测试 const greeting = (name) => `hello ${name}`; const toUpper = (str) => str.toUpperCase(); const fn = compose(toUpper, greeting); console.log(fn("yideng"));
- 实现方式二:迭代实现
function compose(...fns) { let isFirst = true; return (...args) => { return fns.reduceRight((result, fn) => { if (!isFirst) return fn(result); isFirst = false; return fn(...result); }, args); }; }
- lodash.js 库的实现
var flow = function (funcs) { var length = funcs.length; var index = length; while (index--) { if (typeof funcs[index] !== "function") { throw new TypeError("Expected a function"); } } return function (...args) { var index = 0; var result = length ? funcs[index].apply(this, args) : args[0]; while (++index < length) { result = funcs[index].call(this, result); } return result; }; }; var flowRight = function (funcs) { return flow(funcs.reverse()); }; const greeting = (name) => `hello ${name}`; const toUpper = (str) => str.toUpperCase(); const fn = flowRight([toUpper, greeting]); console.log(fn("yideng"));
可以看出,lodash 的本来实现是从左到右实现的,但也提供了从右到左的 flowRight,还多了一层函数的校验,而且接收的是数组,不是参数序列。
本文作者:前端小毛
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!