在使用函数组合解决问题的时候,会使用到lodash中提供的一些方法,但是这些方法有多个参数的时候,需要对这些方法进行柯里化的处理,需要重新包装这些方法稍微有些麻烦, lodash中fp模块,提供了一些实用的对函数式编程友好的方法。提供的方法是不可变的,如果一个方法的参数是函数的话,会要求函数优先并且数据置后。
lodash模块的方法和lodash/fp模块方法的区别
//lodash 模块
const _ = require("lodash");
_.map(["a", "b", "c"], _.toUpper);
//=>['A','B','C']
_.map(["a", "b", "c"]);
//=>['a','b','c']
_.split("Hello World", " ");
lodash模块中的map方法和split方法,map方法可以对数组进行遍历,并且在遍历的过程中可以指定一个函数对数组中的每个元素进行处理,在调用的时候要求数据优先,函数置后,当map方法只传递了一个参数,没有传递这个函数的时候,会原封不动的返回这个数组。
split方法是对字符串进行切割,会要求首先传递数据,再传入分割符。传入的参数都是数据优先,函数置后的。
//lodash/fp模块
const fp = require("lodash/fp");
fp.map(fp.toUpper, ["a", "b", "c"]);
fp.map(fp.toUpper)(["a", "b", "c"]);
fp.split(" ", "Hello World");
fp.split(" ")("Hello World");
再看lodash/fp中提供的这些方法。和上面是相反的,先传入函数再传入数据,如果只传入了一个参数,此时会返回一个新的函数,来等待接收剩余的参数,所以map是一个柯里化的函数,split也是传入一个分割符,返回一个函数等待接收剩余的参数
//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 map = _.curry((fn, array) => _.map(array, fn));
const f = _.flowRight(join("-"), map(_.toLower), split(" "));
console.log(f("NEVER SAY DIE"));
看之前这个例子,这个例子是我上一篇文章里用来演示函数组合如何调试的例子。
我们之前在使用lodash中的方法,来组合成新的函数的时候,需要对split,join,map来进行重新包装,因为这些方法都是数据优先,函数置后,而且没有被柯里化,所以在使用的时候都调了curry函数。
通过fp模块来改造一下代码
const fp = require("lodash/fp");
const f = fp.flowRight(fp.join("-"), fp.map(fp.toLower), fp.split(" "));
console.log(f("NEVER SAY DIE"));
运行结果是一样的。
在lodash和lodash/fp模块中map方法有哪些区别呢?
const _ = require("lodash");
console.log(_.map(["23.3", "8", "10"], parseInt));
打印的结果却是
再看一下lodash/fp中的map
const fp = require("lodash/fp");
console.log(fp.map(parseInt, ["23.3", "8", "10"]));
打印结果才是转成 int后的结果
这两个区别是parseInt接收的参数不一样,lodash中所接收的参数是3个,第一个是要处理的每个元素,第二个是索引(而parseInt第二个参数是转成几进制数),第三个是数组,而lodash/fp中这个map方法他所接收的parseInt函数的参数,只有一个当前处理的元素。
最后再来说说PointFree。
PointFree是一个编程的风格,他的具体实现就是函数的组合,只是感觉更抽象一些
PointFree:我们可以把数据处理的过程定义成与数据无关的合成运算,不需要用到代表数据的那个参数,只要把简单的运算步骤合成到一起,在使用这种模式之前我们需要定义一些辅助的基本运算函数。
- 不需要指明处理的数据
- 只需要合成运算过程 (其实就是函数的组合) - 需要定义一些辅助的基本运算函数
写一个案例吧。
把一个字符串中的首字母提取并转换成大写,使用.作为分隔符。
//world wild web ==>W.W.W
const fp = require("lodash/fp");
const firstLetterToupper = fp.flowRight(
fp.join(". "),
fp.map(fp.first),
fp.map(fp.toUpper),
fp.split(" ")
);
console.log(firstLetterToupper("world wild web"));
上面例子中用到了两次map,每次map都会对数组进行遍历,会导致性能比较低一些,可以再进行一次组合。
const fp = require("lodash/fp");
const firstLetterToupper = fp.flowRight(
fp.join(". "),
fp.map(fp.flowRight(fp.first, fp.toUpper)),
fp.split(" ")
);
console.log(firstLetterToupper("world wild web"));
结果是一样的