函数柯里化(curry)

元宇宙
• 阅读 4544

前言

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

正文

引子-从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

小结

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

点赞
收藏
评论区
推荐文章
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
巴拉米 巴拉米
4年前
bind、call、apply 区别?如何实现一个bind?
一、作用call、apply、bind作用是改变函数执行时的上下文,简而言之就是改变函数运行时的this指向那么什么情况下需要改变this的指向呢?下面举个例子var name"lucy";const obj{    name:"martin",    say:function (){        co
待兔 待兔
1年前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Souleigh ✨ Souleigh ✨
4年前
初识 JS 中的柯里化
作为函数式编程语言,JS带来了很多语言上的有趣特性,比如柯里化。1.简介柯里化(Currying),又称部分求值(PartialEvaluation),是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。核心思想是把多参数传入的函数拆成单参数(或部分)函
菜园前端 菜园前端
2年前
什么是函数组合?
原文链接:什么是函数组合?函数组合(Compose),如果一个函数要经过多个函数处理才能得到最终值,这个时候可以把中间过程的函数合并成一个函数。函数组合默认是从右到左执行,每个函数只能接收一个参数,否则需使用柯里化进行转换。作用函数组合可以让我们把细粒度的
菜园前端 菜园前端
2年前
什么是函数柯里化?
原文链接:什么是函数柯里化?函数柯里化(HaskellBrooksCurry),当一个函数有多个参数的时候先传递一部分参数并且调用它(这部分参数后续不会进行改变),然后返回一个新的函数接收剩余的参数并返回结果。总结柯里化可以让我们给一个函数传递较少的参数得
Wesley13 Wesley13
3年前
Java 8 中的 Lambda 表达式 vs. Kotlin 中的 Lambda
直接上一段Kotlin的函数式编程的代码:packagecom.easykotlin.lec02funsum1(x:Int,y:Int):Int{returnxy}funsum2(x:Int,y:Int)xy//
Stella981 Stella981
3年前
JS 对象数组Array 根据对象object key的值排序sort,很风骚哦
有个js对象数组varary\{id:1,name:"b"},{id:2,name:"b"}\需求是根据name或者id的值来排序,这里有个风骚的函数函数定义:function keysrt(key,desc) {  return function(a,b){    return desc ? ~~(ak
Wesley13 Wesley13
3年前
35岁,真的是程序员的一道坎吗?
“程序员35岁是道坎”,“程序员35岁被裁”……这些话咱们可能都听腻了,但每当触及还是会感到丝丝焦虑,毕竟每个人都会到35岁。而国内互联网环境确实对35岁以上的程序员不太友好:薪资要得高,却不如年轻人加班猛;虽说经验丰富,但大部分公司并不需要太资深的程序员。但35岁危机并不是不可避免的,比如你可以不断精进技术,将来做技术管理或者
Stella981 Stella981
3年前
Python time模块 返回格式化时间
常用命令  strftimetime.strftime("%Y%m%d%H:%M:%S",formattime)第二个参数为可选参数,不填第二个参数则返回格式化后的当前时间日期201812112:00:00time.strftime('%H:%M:%S')返回当前时间的时分秒time.strftim
Stella981 Stella981
3年前
JavaScript中call()与apply()有什么区别?
今天读《JavaScript权威指南》时发现其中有段代码用到了apply方法用于递归实现数组的展开。可是我不懂这个函数的用法,因此查了一下,将资料整理如下。Javascript的每个Function对象中有一个apply方法:function.apply(thisObj,argArray)还有一个类似功能的call方法: