柯里化与反柯里化
柯里化是指 把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数。
核心思想是把多参数传入的函数拆成单参数(或部分)函数,内部再返回调用下一个单参数(或部分)函数,依次处理剩余的参数。
例如
// 传统写法
add(1,2,3)
// 柯里化写法
add(1)(2)(3)
柯里化本质上是降低通用性,提高适用性。比如当我们需要校验手机号
function checkMobile(regExp,mobile) {
return regExp.test(mobile);
}
checkMobile(/^1\d{10}$/, '186****1111'); // 校验电话号码
当需要校验多个手机号,传统写法如下
checkMobile(/^1\d{10}$/, '186****1111'); // 校验电话号码
checkMobile(/^1\d{10}$/, '186****2222'); // 校验电话号码
checkMobile(/^1\d{10}$/, '186****3333'); // 校验电话号码
乍一看也没什么毛病,但是通过柯里化,我们可以更加优雅的对函数进行封装
//函数柯里化
let _check = curry(checkMobile);
//生成工具函数
let checkCellPhone = _check(/^1\d{10}$/);
// 使用
checkCellPhone('186****1111'); // 校验电话号码
checkCellPhone('186****2222'); // 校验电话号码
checkCellPhone('186****3333'); // 校验电话号码
柯里化工具函数
简易实现
// 实现一个add方法,对 [1,2,3] 该数组求和
function sum(x) {
return function (y) {
return function (z) {
return x + y + z
}
}
}
// 调用
sum(1)(2)(3) // 6
// 封装一个简易柯里化工具,实现对普通函数的柯里化
function curry(fn) {
return function (x){
return function (y) {
return function (z) {
return fn(x, y, z);
};
};
}
}
var sum3 = curry(function (x, y, z) {
return x + y + z;
});
console.log(sum3(1)(2)(3)); // 6
如果参数不固定这种封装方法就不够灵活
实现思路
TODO 通过函数的 length 属性,获取函数的形参个数,形参的个数就是所需的参数个数
具体封装
/**
* 函数柯里化
* @param fn 待柯里化的原函数
* @param len 所需的参数个数,默认为原函数的形参个数
*/
function curry(fn,len = fn.length) {
return _curry.call(this,fn,len) // 需要更改this的指向 到【待柯里化的原函数中】
}
/**
* @param fn 待柯里化的原函数
* @param len 所需的参数个数
* @param args 已接收的参数列表
*/
function _curry(fn,len,...args) {
return function (...params) {
let _args = [...args,...params];
if(_args.length >= len){
return fn.apply(this,_args); // 执行原函数
}else{
return _curry.call(this,fn,len,..._args) // 参数累加
}
}
}
使用
let _fn = curry(function(a,b,c,d,e){
console.log(a,b,c,d,e)
});
_fn(1)(2)(3)(4)(5) // 输出: 1,2,3,4,5
反柯里化
与柯里化相对应。
- 反柯里化则是扩大适用范围,创建一个应用范围更广的函数。
- 柯里化是为了缩小适用范围,创建一个针对性更强的函数;