函数式编程四:js函数的组合,调试

纯函数他柯里化很容易写出洋葱代码h(g(f(x)))
比如获取数组的最后一个元素再转换成大写字母,.toUpper(.first(_.reverse(array)));
在这里插入图片描述
函数组合可以让我们把细粒度的函数重新组合生成一个新的函数。
管道
下面张图表示程序中使用函数处理数据的过程,给fn函数输入参数a,返回结果b.可以想想a数据通过一个管道得到了b数据。
在这里插入图片描述
当fn函数比较复杂的时候,我们可以把函数fn拆分成多个小函数,此时多了中间运算过程产生的m和n.
下面这张图中可以想象成把fn这个管道拆分成3个管道f1,f2,f3,数据a通过管道f3得到结果m,m再通过管道f2得到结果n,n通过管道f1得到最终结果b在这里插入图片描述
函数组合
函数组合(compose):如果一个函数要经过多个函数处理才能得到最终值,这个时候可以把中间过程的函数合并成一个函数
函数就像是数据的管理,函数组合就是把这些管道连接起来,让数据穿过多个管道形成最终结果。
函数组合默认是从右到左执行。

function compose(f,g){
    return function(value){
        return f(g(value));
    }
}

function reverse(array){
    return array.reverse();
}

function first(array){
    return array[0];
}
const last=compose(first,reverse);
console.log(last([1,2,3,4]));

上面是一个简单的函数组合例子,先把这个数组反转,再取数组第一个,再compose把这两个方法组合成一个新的函数去调用。从右到左执行,先执行reverse函数,返回的结果再给first去执行。

在lodash中也有组合函数
lodash中组合函数flow()或者flowRight(),他们都可以组合多个函数。
flow()是从左到右运行。
flowRight()是从右到左执行,使用的更多一些

const _ = require("lodash");

const reverse = (arr) => arr.reverse();
const first = (arr) => arr[0];
const toUpper = (s) => s.toUpperCase();

const f = _.flowRight(toUpper, first, reverse);

console.log(f(["one", "two", "three"]));

看了 lodash中如何使用函数组合的,那我们也来模拟 flowRight函数吧。

function compose(...args){
    return function(value){
        return args.reverse().reduce(function(acc,fn){
            return fn(acc);
        },value)
    }
}
const reverse = (arr) => arr.reverse();
const first = (arr) => arr[0];
const toUpper = (s) => s.toUpperCase();

const f = compose(toUpper, first, reverse);

console.log(f(["one", "two", "three"]));

同样的例子把flowRight换成compose函数效果是一样的。也可以简写成

const compose = (...args) => (value) => args.reverse().reduce((acc, fun) => fun(acc), value);

函数的组合要满足结合律(associativity):
我们既可以把g和 h组合,还可以把f和 g结合,结果都 是一样

let f = compose(f, g, h);
let associative = compose(compose(f, g), h) == compose(f, compose(g, h));
//true

调试
现在可以通过函数的组合解决一些问题,当我们使用函数组合的时候,如果组合执行的结果跟我们预期的不一致,怎么去调试这多个函数的时候哪个函数出现的问题呢?我们可以在函数执行之后把结果打印出来。
把NEVER SAY DIE转换成never-say-die

const _ = require("lodash");

const split = _.curry((sep, str) => _.split(str, sep));
const join = _.curry((sep, array) => _.join(array, sep));
const f = _.flowRight(join("-"), _.toLower, split(" "));

console.log(f("NEVER SAY DIE"));

打印出来的结果竟是这样的
在这里插入图片描述
可以写一个log函数把每个函数调用后的值打印出来,看哪个函数最终输出的值有问题再做具体的调试。

const _ = require("lodash");

const log = (v) => {
  console.log(v);
  return v;
};

const split = _.curry((sep, str) => _.split(str, sep));
const join = _.curry((sep, array) => _.join(array, sep));
const f = _.flowRight(join("-"), log, _.toLower, log, split(" "));

console.log(f("NEVER SAY DIE"));

在这里插入图片描述

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值