柯里化  (Haskell Brooks Curry) - 图1

1. 概念

当一个函数有多个参数的时候先传递一部分参数调用它(这部分参数以后永远不变)然后返回一个新的函数接收剩余的参数,返回结果
使用柯里化解决硬编码问题示例:

  1. // 纯函数(有硬编码,后续可以通过柯里化解决)
  2. // function checkAge(age) {
  3. // let min = 18
  4. // return age >= mini
  5. // }
  6. // 普通纯函数
  7. // function checkAge(min,age) {
  8. // return age >= min
  9. // }
  10. // console.log(checkAge(18,20));
  11. // console.log(checkAge(18,25));
  12. // console.log(checkAge(20,20));
  13. // 柯里化函数
  14. function checkAge(min) {
  15. return function(age){
  16. return age >= min
  17. }
  18. }
  19. // 改造为 ES6 箭头函数写法
  20. // let checkAge = min =>(age => age >= min)
  21. let checkAge18 = checkAge(18);
  22. let checkAge22 = checkAge(22);
  23. console.log(checkAge18(20));
  24. console.log(checkAge18(25));
  25. console.log(checkAge22(20));

2. Lodash中的柯里化方法 (_.curry(func))

功能:创建一个函数,该函数接收一个或多个 func 的参数,如果 func 所需要的参数都被提供则执行 func 并返回执行的结果。否则继续返回该函数并等待接收剩余的参数。
(可以把任意多参数的函数转化成一元函数)
参数:需要柯里化的函数
返回值:柯里化后的函数
示例:

  1. // 简单应用Lodash中的柯里化方法(_.curry(func))
  2. const _ = require('lodash');
  3. function getSum(a, b, c) {
  4. return a + b + c;
  5. }
  6. // 通过lodash 转为柯里化函数
  7. const curried = _.curry(getSum);
  8. console.log(curried(1, 2, 3));
  9. console.log(curried(1, 2)(3));
  10. console.log(curried(1)(2)(3));

3. 原理模拟

  1. // 模拟 lodash 中的 curry 方法
  2. function getSum(a, b, c) {
  3. return a + b + c;
  4. }
  5. // 通过lodash 转为柯里化函数
  6. const curried = curry(getSum);
  7. // console.log(curried(1, 2, 3));
  8. console.log(curried(1, 2)(3));
  9. // console.log(curried(8)(9)(10));
  10. // 模拟lodash 中的 curry 方法
  11. function curry(func) {
  12. return function curriedFn(...args) {
  13. console.log('----------------------', args);
  14. // 实参和形参进行对比
  15. if (args.length < func.length) {
  16. return function () { // 一定要闭包 因为实参小于形参 相对于下一个括号里的东西
  17. // concat() 方法用于连接两个或多个数组。
  18. // from() 通过给定的对象中创建一个数组。
  19. // 上一个参数被 上面的 args 记录了 arguments这个指的是下一个参数
  20. console.log(args.concat(Array.from(arguments)));
  21. // 将连接好的数组打散再传给curriedFn 进行递归 一直到括号都走完(形参==实参)
  22. return curriedFn(...args.concat(Array.from(arguments)))
  23. }
  24. }
  25. return func(...args)
  26. }
  27. }

4. 案例:寻找数组中的带有空白字符的元素

  1. // 寻找数组中的带有空白字符的元素
  2. const _ = require('lodash');
  3. // match() 方法可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配。
  4. const match = _.curry(function(reg,str){
  5. return str.match(reg)
  6. })
  7. // 正则表达式 \s 匹配任何空白字符
  8. // "g"表示全局匹配将替换所有匹配的子串,如果不加"g"当匹配到第一个后就结束了
  9. const haveSpace = match(/\s+/g)
  10. // \d是指数字
  11. const haveNumber = match(/\d+/g)
  12. // 数组过滤
  13. const filter = _.curry(function(func,array){
  14. return array.filter(func)
  15. })
  16. // 寻找带空格的元素
  17. const findSpace = filter(haveSpace);
  18. console.log(filter(haveSpace,['aa aa','bbbb']));
  19. console.log(findSpace(['aa aa','bbbb']));

5. 总结

  1. 这是一种对函数参数的’缓存’ (因为使用了闭包的原因)
  2. 柯里化可以让我们给一个函数传递较少的参数得到一个已经记住了某些固定参数的新函数
  3. 让函数变的更灵活,让函数的粒度更小
  4. 可以把多元函数转换成一元函数,可以组合使用函数产生强大的功能