javascript实现柯里化函数

26 阅读2分钟

学了一天,人都麻了。。。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>柯里化函数</title>
</head>
<body>
  <script>
    //一个函数需要传入多个参数,现在把这个函数进行柯里化,
    // 新的函数允许可以接收单个参数或多个参数,链式调用进行最终的函数执行
    //简单的例子
    function add(a,b,c){
      return a+b+c
    }
    //柯里化后的函数
    function curriedAdd(a){
      return function (b){
        return function(c){
          return a+b+c
        }
      }
    }
    const res = curriedAdd(1)(2)(3)
    console.log(res);
    //步骤分解:
    //第一次调用返回一个函数
    const step1 = curriedAdd(1)
    //第二次调用返回一个函数
    const step2 = step1(2)
    //第三次调用返回结果
    const resC = step2(3)//数据是通过闭包保存下来的,所以里面的函数能用。
    console.log(resC);
    //原本需要一次传递三个参数,现在只需一个一个传递了,但是最后还是执行的原函数的代码


    //通用的柯里化函数,将一个函数转成柯里化函数
    function curry(fn){
      return function curried(...args){
        //柯里化函数,核心逻辑
        if(args.length >= fn.length){//参数够了直接执行当前函数并返回
            return fn.apply(this,args)
        }else{//参数不够,将参数逐一添加进去,返回新的函数,函数的返回值是执行本回调函数的结果
          return function (...args2){
              return curried.apply(this,args.concat(args2))
          }
        }
      }
    }

    const curriedNew = curry(add)
    const resNew = curriedNew(1)(2)(3)
    console.log(resNew);
    //步骤拆解:
    //curriedNew 是一个柯里化的函数
    //curriedNew(1)
    //add的参数大于传来的长度,走else
    //返回一个函数记录为steps1
    //const steps1 = function (...args2){
          //     return curried.apply(this,args.concat(args2)) 此时args为[1],闭包记住了
          // }
    //然后curriedNew(1)(2)等价于steps1(2)
    //返回curried.apply(this,args.concat(args2))的执行结果,此时[1,2]
    //add的参数还是大于传来的长度,返回一个函数记录为steps2
    // const steps2 = function (...args2){
    //           return curried.apply(this,args.concat(args2))//此时的args为[1,2]
    //       }
    //最后curriedNew(1)(2)(3)等价于steps2(3)
    //返回curried.apply(this,args.concat(args2))的执行结果,此时后面为[1,2,3]
    //递归发现长度相等了,就返回:执行fn.apply(this,args)此时args为[1,2,3]执行原来的函数。
    //最终返回a+b+c

    const resNews = curriedNew(1,2)(3)
    console.log(resNews);
    //第一步返回一个柯里化的函数curriedNew
    //curriedNew(1,2)
    //传来的参数数量小于原函数所需的参数,走else
    //返回一个函数
    // function (...args2){
    //           return curried.apply(this,args.concat(args2))此时的args为[1,2],闭包在记录着
    //       }
    //然后curriedNew(1,2)(3)
    //返回curried.apply(this,args.concat(args2))的执行结果,此时后面这部分的值为[1,2,3]
    // 然后递归调用发现参数数量相等,然后走上面的分支
    // 返回curried.apply(this,args.concat(args2))执行结果,就是1+2+3


    //为什么使用>=号?
    function aa(a,b,c){
      return a+b+c
    }
    console.log(aa(1,2,3,4));//正常会忽略4的
    //避免传过来的值过多而出现逻辑错误。可以接收多余参数。
  </script>
</body>
</html>