函数柯里化 curry

是把接收多个参数的函数变换成接收一个单一参数(最初函数的第一个参数)的函数,
并且返回接收余下的参数而且返回结果的新函数的技术。
表现形式上就是函数里面返回函数(闭包

用处:

1.参数复用
2.兼容性检测
3.延迟执行(对参数复用功能进行改进)

1.参数复用

  1. // (1)正常正则验证字符串 reg.test(txt)
  2. // 函数封装后
  3. function check(reg, txt) {
  4. return reg.test(txt)
  5. }
  6. check(/\d+/g, 'test') //false
  7. check(/[a-z]+/g, 'test') //true
  8. // Currying后
  9. function curryingCheck(reg) {
  10. return function (txt) {
  11. return reg.test(txt)
  12. }
  13. }
  14. var hasNumber = curryingCheck(/\d+/g)
  15. var hasLetter = curryingCheck(/[a-z]+/g)
  16. hasNumber('test1') // true
  17. hasNumber('testtest') // false
  18. hasLetter('21212') // false

2.兼容性写法

  1. const whichEvent = (function () {
  2. if (window.addEventListener) {
  3. // 主流浏览器,事件冒泡事件捕获
  4. return function (ele, type, listener, useCapture) {
  5. ele.addEventListener(type, function (e) {
  6. listener.call(ele, e)
  7. }, useCapture)
  8. }
  9. } else if (window.attachEvent) {
  10. // ie 事件冒泡
  11. return function (ele, type, handler) {
  12. ele.attachEvent(`on${type}`, function (e) {
  13. handler.call(ele, e)
  14. })
  15. }
  16. }
  17. })()

3.延迟执行

  1. /*
  2. 经典面试题实现
  3. 实现add函数,实现一下计算结果
  4. add(1)(2)(3) = 6;
  5. add(1,2,3)(4) = 10;
  6. add(1)(2)(3)(4)(5) = 15;
  7. */
  8. /*
  9. 分析:
  10. 1.对传入参数不限定
  11. 2.不能丢失传入的参数
  12. 3.什么时候传入参数都可以(不同时期传入的参数可以和已传入的参数一起使用)
  13. */
  14. // (1)基础版
  15. function add() {
  16. let args = Array.prototype.slice.call(arguments);
  17. let inner = function () {
  18. args.push(...arguments)
  19. let sum = args.reduce(function (preSum, cur) {
  20. return preSum + cur
  21. })
  22. return sum
  23. }
  24. return inner;
  25. }
  26. console.log(add(1)(2)) // 3
  27. console.log(add(1)(2)(3))
  28. /*
  29. Uncaught TypeError: add(...)(...) is not a function
  30. at <anonymous>:1:22
  31. */
  32. // (2)用递归处理参数不定情况
  33. function add() {
  34. let args = Array.prototype.slice.call(arguments);
  35. let inner = function () {
  36. args.push(...arguments)
  37. return inner // 内部函数已经返回了内部函数,很难再返回一个额外的结果到外部 => 修改toString方法
  38. }
  39. return inner;
  40. }
  41. console.log(add(1)(2)(3)(4))
  42. // 原本的函数被转换成字符串显示了,其实就是发生了隐式转换,发生隐式转换是因为调用了内部的toString方法
  43. /*
  44. ƒ () {
  45. args.push(...arguments)
  46. return inner
  47. }
  48. */
  49. // (3)修改toString方法,并在里面处理返回值
  50. function add() {
  51. // 定义args存储所有参数
  52. let args = Array.prototype.slice.call(arguments);
  53. // 内部声明一个函数,利用闭包的特性保存args, 进行参数收集
  54. let inner = function () {
  55. args.push(...arguments)
  56. return inner
  57. }
  58. inner.toString = function () {
  59. return args.reduce(function (preSum, cur) {
  60. return preSum + cur
  61. })
  62. }
  63. return inner;
  64. }
  65. console.log(add(1)(2)(3)(4)) // ƒ 10 函数类型

上面的写法不正确

思路:

  1. 参数收集
  2. 收集完毕,执行函数 ```javascript // 参数只能从左到右传递 function createCurry(func, arrArgs) { var args=arguments; var funcLength = func.length; var arrArgs = arrArgs || [];

    return function() {

    1. var _arrArgs = Array.prototype.slice.call(arguments);
    2. var allArrArgs=arrArgs.concat(_arrArgs)
    3. // 如果参数个数小于最初的func.length,则递归调用,继续收集参数
    4. if (allArrArgs.length < funcLength) {
    5. return args.callee.call(this, func, allArrArgs);
    6. }
    7. // 参数收集完毕,则执行func
    8. return func.apply(this, allArrArgs);

    } }

// createCurry 返回一个柯里化函数 var sumCurry=createCurry(function(a, b, c) { return a + b + c; }); sumCurry(1)(2)(3) // 6 sumCurry(1, 2, 3) // 6 sumCurry(1)(2,3) // 6 sumCurry(1,2)(3) // 6 ```