函数柯里化
一、定义
在计算机科学中,柯里化(英语:Currying),指的是把“接受多个参数的函数”变换成“接受单一参数(最初函数的第一个参数) 的函数”,并返回“接受余下的参数而且返回结果的新函数“的技术。
顾名思义,柯里化其实本身是固定一个可以预期的参数,并返回一个特定的函数,处理特定的需求。这增加了函数的适用性,但同时也降低了函数的通用性。
这样的定义不太好理解,我们可以通过下面的例子配合解释:
function A(a, b) {
return a + b
}
将函数A转化为柯里化函数 _A:
function _A(a){
return function(b){
return a + b
}
}
那么 _A 作为柯里化函数,他能够处理A的剩余参数。因此下面的运行结果是等价的。
A(1, 2);
_A(1)(2);
_A能够处理A的所有剩余参数,因此柯里化也被称为部分求值。
实际上就是把A函数的a,b两个参数变成了先用一个函数接收a然后返回一个函数去处理b参数。
现在思路应该就比较清晰了,只传递给函数一部分参数来调用,让它返回一个函数去处理剩下的参数
二、柯里化的通用实现
柯里化,是函数式编程的一个重要概念。它既能减少代码冗余,也能增加可读性。
现在看一个更复杂一点的例子,sum 是个简单的累加函数,接受3个参数,输出累加的结果:
function sum (a, b, c) {
console.log(a + b + c);
}
假设有这样的需求,sum的前2个参数保持不变,最后一个参数可以随意。那么就会想到,在函数内,是否可以把前2个参数的相加过程,给抽离出来,因为参数都是相同的,没必要每次都做运算。调用的写法可以是这样: sum(1, 2)(3)或sum(1, 2)(10),先把前2个参数的运算结果拿到后,再与第3个参数相加。这其实就是函数柯里化的简单应用。
sum(1, 2)(3)这样的写法,并不常见。拆开来看sum(1, 2) 返回的应该还是个函数,因为后面还有 (3) 需要执行。那么反过来,从最后一个参数,从右往左看,它的左侧必然是一个函数。以此类推,如果前面有n个(),那就是有n个函数返回了结果,只是返回的结果还是一个函数。是不是有点递归的意思?
function curry (fn, currArgs) {
return function() {
let args = [].slice.call(arguments);
// 首次调用时,若未提供最后一个参数currArgs,则不用进行args的拼接
if (currArgs !== undefined) {
args = args.concat(currArgs);
}
// 递归调用
if (args.length < fn.length) {
return curry(fn, args);
}
// 递归出口
return fn.apply(null, args);
}
}
说明:
- curry有 2 个参数,fn 指的就是源处理函数 ;currArgs 是调用 curry 时传入的参数列表
- 将 arguments 数组化,arguments 是一个类数组的结构,它并不是一个真的数组,所以没法使用数组的方法。我们用了 call 的方法,就能愉快地对 args 使用数组的原生方法了。
- args指的是当前柯里化的函数内已获得的所有参数,这个函数最终会传给fn
- 判断 args 的个数,是否与 fn (也就是 sum )的参数个数相等,相等了就可以把参数都传给 fn,进行输出;否则,继续递归调用,直到两者相等。
三、柯里化的作用
1.参数复用
案例:正则验证字符串
按照普通的思路,验证字符串是否是正确的手机号或者邮箱
//验证手机号
function checkPhone(phoneNumber) {
return /