原函数
let add = (a,b) =>a+b
add(1,2) // 3
经过柯里化之后
let addCurry = curry(add)
addCurry(1)(2) //3
在某些场景中 ,我们需要给一组数据进行统一操作 例如+1 就可利用柯里化 addCurry(1)(x) 此处x为需要进行操作的数据
函数柯里化的通用版本
es5 :
function add(x){
return function(y){
return y + x
}
}
es6 :
let add = (a) =>(b) =>a+b
第一次看到柯里化这个词的时候,还是在看一篇算法相关的博客提到把函数柯里化,那时一看这个词就感觉很高端,实际上当你了解了后才发现其实就是高阶函数的一个特殊用法。
果然是不管作用怎么样都要有个高端的名字才有用。
看这个解释有一点抽象,我们就拿被做了无数次示例的add函数,来做一个简单的实现。
实际上就是把add函数的x,y两个参数变成了先用一个函数接收x然后返回一个函数去处理y参数。现在思路应该就比较清晰了,就是只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。
但是问题来了费这么大劲封装一层,到底有什么用处呢?没有好处想让我们程序员多干事情是不可能滴,这辈子都不可能.
上面的示例是一个正则的校验,正常来说直接调用check函数就可以了,但是如果我有很多地方都要校验是否有数字,其实就是需要将第一个参数reg进行复用,这样别的地方就能够直接调用hasNumber,hasLetter等函数,让参数能够复用,调用起来也更方便。
我们在做项目的过程中,封装一些dom操作可以说再常见不过,上面第一种写法也是比较常见,但是我们看看第二种写法,它相对一第一种写法就是自执行然后返回一个新的函数,这样其实就是提前确定了会走哪一个方法,避免每次都进行判断。
像我们js中经常使用的bind,实现的机制就是Currying.
说了这几点好处之后,发现还有个问题,难道每次使用Currying都要对底层函数去做修改,
这边首先是初步封装,通过闭包把初步参数给保存下来,然后通过获取剩下的arguments进行拼接,最后执行需要currying的函数。
但是好像还有些什么缺陷,这样返回的话其实只能多扩展一个参数,currying(a)(b)(c)这样的话,貌似就不支持了(不支持多参数调用),一般这种情况都会想到使用递归再进行封装一层。
这边其实是在初步的基础上,加上了递归的调用,只要参数个数小于最初的fn.length,就会继续执行递归。
curry的一些性能问题你只要知道下面四点就差不多了:
概念:把接受多个参数的函数转换成接受一个单一参数的函数。简洁版的柯里化函数:
简洁版的柯里化函数缺点:每次只能传递两个实参,计算两个实参的和,如果想计算多个实参的和,无法实现。
稍微复杂点的柯里化函数:
上面柯里化函数的特点:传入多少个参数就能计算出这些参数的总和,但是最后要有个结束标志,传入参数为空,表示到此截止,把前面参数的总和计算一下。
通用的柯里化函数:
上面通用柯里化函数特点:可以根据add()的参数个数进行计算,假如add(a,b)有2个参数,就计算a+b;假如add(a,b,c)有3个参数,就计算a+b+c有4个参数就计算4个参数的和,依此类推。