函数柯里化 只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数 ,函数性编程的重要体现

  1. function curry(func) {
  2. return function curried(...args) {
  3. // 关键知识点:function.length 用来获取函数的形参个数
  4. // 补充:arguments.length 获取的是实参个数
  5. if (args.length >= func.length) {
  6. return func.apply(this, args)
  7. }
  8. return function (...args2) {
  9. return curried.apply(this, args.concat(args2))
  10. }
  11. }
  12. }
  13. // 测试
  14. function sum (a, b, c) {
  15. return a + b + c
  16. }
  17. const curriedSum = curry(sum)
  18. console.log(curriedSum(1, 2, 3))
  19. console.log(curriedSum(1)(2,3))
  20. console.log(curriedSum(1)(2)(3))

01 减少重复传递不变的部分参数

进一步对于某一个数据的进行封装,进行复用,这样可以对于一个类进行自主化的二次分装

  1. function simpleURL(protocol, domain, path) {
  2. return protocol + "://" + domain + "/" + path;
  3. }

然后你会发现,前两个参数保持不变,但每次调用都需要传递。所以可以对其优化,仅传递最后一个变化的参数。
通常我们第一个想法是将函数改成如下:

  1. function simpleURL(path) {
  2. return "http://mysite/" + path;
  3. }

但是还是有点缺陷,如果这个库函数有被其它人使用呢,这种情况下基本上是不允许直接改库函数的。并且如果后期还需要处理https的请求呢。难道再把第一个参数加回去?这样别人若使用了该库函数也要修改调用代码。
针对这种情况,使用柯里化函数可以完美解决。

使用lodash.curry库函数使函数柯里化
**

  1. // 避免每次调用重复传参
  2. let myURL1 = _.curry(simpleURL)('https', 'mysite');
  3. let res1 = myURL1('home.html'); //
  4. console.log(res1);//https://mysite/home.html
  5. let myURL2 = _.curry(simpleURL)('http', 'mysite');
  6. let res2 = myURL2('aboutme.html'); //
  7. console.log(res2);//http://mysite/aboutme.html

02 将柯里化后的callback参数传递给map, filter等函数。

var persons = [{name: ‘kevin’, age: 11}, {name: ‘daisy’, age: 24}]
如果我们要获取所有的 name 值,我们一般会这样实现:

  1. var names = persons.map(function (item) {
  2. return item.name;
  3. });

我们可以利用柯里化改写成如下:

  1. var getProp = _.curry(function (key, obj) {
  2. return obj[key]
  3. });
  4. var names = persons.map(getProp('name'))

我们为了获取 name 属性还要再编写一个 getProp 函数,是不是又麻烦了些?
但是请注意,getProp 函数编写一次后,以后可以多次使用,实际上代码从原本的三行精简成了一行,而且你看代码是不是更加易懂了?

demo:

  1. var persons = [{name: 'kevin', age: 11}, {name: 'daisy', age: 24}]
  2. let getProp = _.curry(function (key, obj) {
  3. return obj[key]
  4. });
  5. let names2 = persons.map(getProp('name'))
  6. console.log(names2); //['kevin', 'daisy']
  7. let ages2 = persons.map(getProp('age'))
  8. console.log(ages2); //[11,24]

在这个场景中,将callback柯里化之后,就能实现callback的复用了,而且非常灵活,这样不需要每次map计算都新写一个匿名函数,并在回调里加上特有的逻辑,导致其无法重用。

从上面的例子中还可以看出,无论想要获取抽取出哪个属性值,只要这要写person.map(getProp(‘propertyname_xxx’))就可以轻松获取了。