函数柯里化(curry)

16

前言

(话不多说,填之前的坑)

正文

引子-从apply说函数应用

在js里,我们对于function的用法,可能大部分情况下都还是处于调用,形如

function add(x, y) {
    return x + y
}
console.log(add(1, 2)) //函数调用 返回3

但是有一个apply()函数,使我们拥有另一种方式来应用函数,例如

function add(x, y) {
    return x + y
}
console.log(add.apply(null, [1, 2])) //返回3

apply的第一个参数为null时,this指向全局对象(忘记请自行查阅查mdn),在上面这个例子里,通过apply来应用函数的时候,效果和调用函数完全一致。

部分应用

从前文可知,函数调用就是让一个参数集合(前面的[1,2])应用到函数(前文的add函数)中,那部分应用就是考虑只传递部分参数,而非所有参数。 还是上面add函数的例子,我们希望实现下面的形式(在下一节具体实现):

var newAdd = add.apply(null,[1])//部分应用 只传递了第一个参数
newAdd.apply(null,[2]) //3

分析上面的代码可知,实现部分应用的关键是:部分应用的返回结果是一个新的函数,该函数可以被传入其他参数再次调用

柯里化(curry)

现在进入正题,前面讲完了部分应用。curry化的含义,就是使函数理解并处理部分应用的过程

继续按照上文的思路实现add函数的curry化:

function add(x, y) {
    // 如果只传递部分参数,则部分应用,返回一个新的函数
    if (y === undefined) {
      return function (y) {
        return x + y
      }
    }
    return x + y //如果传递所有参数,直接完全应用
}
//运行前一节代码
var newAdd = add.apply(null, [1])
console.log(newAdd.apply(null, [2])) //3
console.log(newAdd.apply(null, [5])) //6

上述代码已经实现了前一节的要求,可以看到curry的结果就是:经过一次curry的newadd函数,变成一个与1求和的函数,接应用的时候只传递一个参数,都能得到对应的结果,同时也可以看出这个curry太局限。接下来我们就要考虑,如何实现通用的curry函数

通用curry函数

先回忆前面的过程,来思考curry一个函数的实现步骤:

  1. 保存调用curry函数时传入的参数,返回一个新函数(即柯里化执行结果)
  2. 结果函数在被调用后,要让新的参数和旧的参数一起应用的入参函数中

注:入参函数-要被curry的函数,结果函数-被curry之后的函数*

文字比较抽象,可以直接看实现在回来看过程:

  function commonCurry(fn) {
    var slice = Array.prototype.slice,
      storedArgs = slice.call(arguments, 1) //使用slice是为了把arguments转换成真正的数组,剥离此处第一个参数,是因为第一个参数是fn
    return function () {
      var newArgs = slice.call(arguments), //新传入的参数
        args = storedArgs.concat(newArgs)
      return fn.apply(null, args)
    }
  }

  //使用举例
  function add(a, b) {
    return a + b
  }
  var newAdd = commonCurry(add, 10)
  console.log(newAdd(5))
  
  // 多个参数
  function add2(a, b, c, d) {
    return a + b + c + d
  }
  var newAdd2 = commonCurry(add2, 10, 10)
  console.log(newAdd2(5, 4))//29
  
  // 多次curry
  var newAdd3 = commonCurry(newAdd2, 10)
  console.log(newAdd3(10))//40

小结

之后会尝试以更简洁明了的方式来写文章。如果内容有错误的地方欢迎指出(觉得看着不理解不舒服想吐槽也完全没问题);如果对你有帮助,欢迎点赞和收藏,转载请征得同意后著明出处,如果有问题也欢迎私信交流,主页添加了邮箱地址。


如果觉得我的文章对你有用,请随意赞赏

你可能感兴趣的

载入中...