柯里化(currying)是把接受多个参数的函数变换成接受一个参数的函数,并且返回接受剩余参数且返回结果的新函数的技术。
柯里化后的函数接收参数的数量与原函数的形参数量相等时,执行原函数;当接收的参数数量小于原函数形参数量时,返回一个用于接收剩余参数的函数。

// 1 只能传被柯里化函数形参的个数,多少都不行
function currying(fn, ...args) {
const length = fn.length;
return function(...newArgs) {
const allArgs = [...args, ...newArgs];
if (allArgs.length < length) {
return currying.call(this, fn, ...allArgs);
} else {
return fn.apply(this, allArgs);
}
}
}
const add = (a, b, c) => a + b + c;
const addCurrying = currying(add);
console.log(addCurrying(1)(2)(3));
console.log(addCurrying(1,2)(3));
console.log(addCurrying(1)(2,3));
console.log(addCurrying(1,2,3));
// 2 参数长度不固定,最后需要手动调用一次
function currying(fn, ...args) {
let allArgs = [...args];
return function temp(...newArgs) {
if (newArgs.length) {
allArgs = [...allArgs, ...newArgs];
return temp;
} else {
const res = fn.apply(this, allArgs);
allArgs = [...args];
return res;
}
}
}
const add = (...args) => args.reduce((a, b) => a + b);
const addCurrying = currying(add);
console.log(addCurrying(1)(2)(3)(4,5)());
console.log(addCurrying(1)(2)(3,4,5)());
console.log(addCurrying(1)(2,3,4,5)());柯里化用途
// 1 校验规则
// 原函数
function checkByRegExp(regExp, string) {
return regExp.test(string);
}
// 普通使用
checkByRegExp(/^1d{10}$/, '18642838455'); // 校验电话号码
checkByRegExp(/^(w)+(.w+)*@(w)+((.w+)+)$/, 'test@163.com'); // 校验邮箱
// 柯里化后使用
let check = currying(checkByRegExp);
let checkCellPhone = check(/^1d{10}$/);
let checkEmail = check(/^(w)+(.w+)*@(w)+((.w+)+)$/);
checkCellPhone('18642838455'); // 校验电话号码
checkCellPhone('13109840560'); // 校验电话号码
checkCellPhone('13204061212'); // 校验电话号码
checkEmail('test@163.com'); // 校验邮箱
checkEmail('test@qq.com'); // 校验邮箱
checkEmail('test@gmail.com'); // 校验邮箱
// 2 提取对象数组的某一属性
const list = [
{name:'lucy'},
{name:'jack'}
];
// 普通使用
const names = list.map(item => item.name);
// 柯里化使用
const prop = currying((key, obj) => obj[key]);
const names = list.map(prop('name'));