一、高阶函数
    一个接受函数参数的函数为高阶函数。
    不管是函数声明还是函数表达式,函数都指向一个变量。
    高阶函数的优点:
    (1)对函数内部功能进行抽象,可以传入自定义方法,还可以扩展功能
    (2)函数参数可以作为函数执行后的回调函数执行

    1. let test = function(a, b, fn){
    2. return fn(a) + fn(b)
    3. }
    4. function powFn(a){
    5. return Math.pow(a,a)
    6. }
    7. let res = test(1,2,powFn)

    不是什么时候都硬要写高阶函数

    1. function test(a, b, fn){
    2. return fn(a, b)
    3. }
    4. 这里的高阶函数的功能只是去调用computor, 没有自己的功能
    5. function computor(a, b){
    6. return a + b
    7. }
    8. console.log(test(1,2,computor))

    如果一个高阶函数的功能只是调用另一个函数,就违背了函数单一功能的原则。

    1. funtion test (fn){
    2. return doSth(function(data){
    3. return fn(data)
    4. })
    5. }
    6. function doSth(fn){
    7. return fn()
    8. }
    9. function add (a,b){
    10. return a + b
    11. }
    12. let myFn = test(add)
    13. myFn => doSth(function(data){ return add(data)}) => function(data){return add(data)}() => return add(data)

    二、函数柯理化
    js函数执行时,不关心是否传参或者参数个数类型。当函数需要完整参数才能执行时,柯理化就派上用场了。
    curry(add(1,2), 3,4) === curry(add(1), 2, 3, 4),当参数没传够的时候,函数执行后返回一个函数,再接受参数,知道参数接收完成时,将函数汇总进行计算。
    特点:
    (1)简化代码,经过柯理化后,很多逻辑都封装在柯理化函数中,只有只需要传参。
    (2)提高维护性,柯理化函数返回的函数,是在一个函数体类产生,易维护。
    (3)功能单一化,一个函数体内可能由多个任务组成,需要将多个单一功能函数组合起来。

    1. function curry(fn){
    2. let args = [].slice.call(arguments, 1);
    3. return function(){
    4. let innerArgs = Array.from(arguments),
    5. combinedArgs = args.concat(innerArgs);
    6. return fn.apply(this, combinedArgs)
    7. }
    8. }
    9. function add(a,b,c,d){
    10. return a + b + c + d
    11. }
    12. let cum1 = curry(add, 1),
    13. cum2 = curry(add, 1,2);
    14. console.log(cum1(2,3,4))
    15. console.log(cum2(3,4))

    三、柯理化工具函数封装
    核心步骤,在没接受到足够数量参数时,不执行传入的原函数,返回具有参数判断功能、并包含已传参数的新函数;这个函数在执行时会判断累计的参数是否够数,如果不够则继续返回相同功能的新函数。

    1. function curryFunc(fn,length){
    2. //fn第一次是工具函数,第二次是包含了已传参数的函数
    3. let len = length || fn.length;
    4. //len 来保存待接收参数个数,第一次调用时保存柯理化函数的形参个数,后面用来保存待接受参数个数
    5. //单层函数柯理化方法
    6. function singleStepCurry(foo){
    7. let outterArgs = [].slice.call(arguments,1);
    8. return function(){
    9. let innerArgs = [].slice.call(arguments),
    10. combinedArgs = outterArgs.concat(innerArgs);
    11. //最开始没有返回函数执行结果
    12. return foo.apply(this,combinedArgs)
    13. }
    14. //处理以后,返回包含之前参数和原函数的新函数。
    15. }
    16. return function(){
    17. let length = arguments.length,
    18. currentArgs = Array.from(arguments),
    19. formattedArr = [fn].concat(currentArgs);
    20. //判断参数是否已经接受完毕
    21. if(len > length){
    22. console.log('len',len,'length',length)
    23. let fnCurriedWithArgs = singleStepCurry.apply(this, formattedArr);
    24. return curryFunc( fnCurriedWithArgs , len - length)
    25. // len - length为还需接受参数个数
    26. }else{
    27. //之前没有返回函数执行结果
    28. return fn.apply(this, currentArgs)
    29. }
    30. }
    31. }
    32. function add (a,b,c,d,e){
    33. return a + b + c + d + e
    34. }
    35. var computor = curryFunc(add);
    36. console.log(computor(1,2,3,4))
    1. function curry (fn, length){
    2. //每次更新待接收参数
    3. let len = length || fn.length;
    4. //单层柯理化工具函数
    5. function singleStepCurry (fn){
    6. let outterArgs = [...arguments].slice(1); //没有把原函数排除
    7. return function(){
    8. let innerArgs = [...arguments],
    9. accumulatedArgs = outterArgs.concat(innerArgs);
    10. console.log(innerArgs,accumulatedArgs)
    11. return fn.apply(this,accumulatedArgs)
    12. }
    13. }
    14. return function(){
    15. let currentArgs = Array.prototype.slice.call(arguments),
    16. currentLength = currentArgs.length;
    17. console.log(currentLength)
    18. //判断参数是否够数如果参数没够,再执行一次单层柯理化
    19. if(len > currentLength){
    20. let formattedArr = [fn].concat(currentArgs),
    21. curriedFunc = singleStepCurry.apply(this, formattedArr); //之前没有使用apply传了个数组
    22. return curry(curriedFunc, len - currentLength)
    23. }else{
    24. //fn是每次记录之前参数的函数,里面也包含了原函数。
    25. console.dir(fn)
    26. return fn.apply(this, currentArgs)
    27. }
    28. }
    29. }
    30. function add (a,b,c,d,e){
    31. return a + b + c + d + e
    32. }
    33. let addingComputor = curry(add);
    34. console.log(addingComputor(1)(2)(3)(4)(5))

    最终执行的函数里面嵌套这许多之前返回的匿名函数

    1. function(){
    2. // outterArgs => [3]
    3. let innerArgs = [...arguments], // innerArgs => [4]
    4. accumulatedArgs = outterArgs.concat(innerArgs); // accumulatedArgs=> [3,4]
    5. return (function(){
    6. let innerArgs = [...arguments],//[3,4]
    7. accumulatedArgs = outterArgs.concat(innerArgs); //outterArgs => [2]
    8. return (function(){
    9. let innerArgs = [...arguments],
    10. accumulatedArgs = outterArgs.concat(innerArgs); //outterArgs => [1]
    11. return fn.apply(this,accumulatedArgs) // accumulatedArgs => [1,2,3,4]
    12. }).
    13. apply(this,accumulatedArgs) // accumulatedArgs => [2,3,4]
    14. })
    15. .apply(this,accumulatedArgs) // accumulatedArgs => [3,4]
    16. }

    如下图:
    image.png