js实现函数柯里化

920 阅读2分钟

解释:只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。

首先实现add(1)(2)(3)

const add = function(x){
    return function(y){
        return function(z){
            return x+y+z
        }
    }
}
console.log(add(1)(2)(3));

简化为箭头函数的形式

const add = x => y => z => x + y + z;
console.log(add(1)(2)(3));

此时函数的形参只能是一个,为了实现下面的结构,得重新写

add(1)(2)
add(1)(2)(3add(1, 2)(3);
add(1)(2, 3);

如果仅仅实现两个括号add(1)(2),可以通过内部return 一个函数来接收第二个括号的函数参数。

    function sum(){
      var args = Array.prototype.slice.call(arguments)
      //1.伪数组转化为数组
      let inner = function(){
        args.push(...arguments)
        //3.将return出去的inner接收的参数放入到args中,此处用到了闭包。
        let total = args.reduce((prev,item) => prev+item)
        return total
      }
      return inner
      //2.将inner返回出去接收其余参数
    }
    console.log(sum(6)(2))

此处,仅仅只能接收两次函数参数,如果为了接收更多参数就需要在inner内再返回一个函数,对于更复杂的场景,明显不适用。

通过在inner里面继续return inner来实现函数参数的收集但是由于函数内部已经return了,所以无法再对args进行处理并return出来

function sum(){
      var args = Array.prototype.slice.call(arguments)
      let inner = function(){
        args.push(...arguments)
        console.log(args)
        return inner
      }
      return inner
    }

通过改写toString方法来实现

    function sum(){
      var args = Array.prototype.slice.call(arguments)
      let inner = function(){
        args.push(...arguments)
        return inner
      }
      inner.toString = function(){
        return args.reduce((prev,curr) => prev+curr)
      }
      return inner
    }

以上是实现了sum方法,此时传入的参数可以不限定

若限定传入的参数为3

比如:sum(1)(2)(3)

可以封装一个curry函数来实现

  var sum = function(a,b,c){
    return a+b+c
  }
  console.log(sum.length)
  function curry(fn, currargs){
    return function (){
      let args = Array.prototype.slice.call(arguments)
      if(currargs != undefined){
        args = args.concat(currargs)
      }
      //递归调用
      if(args.length < fn.length){
        return curry(fn,args)
      }
      //fn.length返回的是fn参数的个数
      if(args.length == fn.length){
        return fn.apply(null,args)
      }else{
        return "error"
      }  
    }
  }
  var fn = curry(sum)
  console.log(fn(1)(2)(3))//6