例:
//普通函数
function fn(a, b, c, d, e) {
console.log(a, b, c, d, e)
}
//生成的柯里化函数
let _fn = curry(fn)
_fn(1, 2, 3, 4, 5) // print: 1,2,3,4,5
_fn(1)(2)(3, 4, 5) // print: 1,2,3,4,5
_fn(1, 2)(3, 4)(5) // print: 1,2,3,4,5
_fn(1)(2)(3)(4)(5) // print: 1,2,3,4,5
柯理化函数的实现
function add () {
let x=0;
for(let i=0;i<arguments.length;i++){
x+=arguments[i];
}
return x;
}
// 对求和函数做curry化
let f1 = curry(add, 1, 2, 3)
console.log('复杂版', f1()) // 6
// 对求和函数做curry化
let f2 = curry(add, 1, 2)
console.log('复杂版', f2(3)) // 6
// 对求和函数做curry化
let f3 = curry(add)
console.log('复杂版', f3(1, 2, 3)) // 6
// 复杂版curry函数可以多次调用,如下:
console.log('复杂版', f3(1)(2)(3)) // 6
console.log('复杂版', f3(1, 2)(3)) // 6
console.log('复杂版', f3(1)(2, 3)) // 6
// 复杂版(每次可传入不定数量的参数,当所传参数总数不少于函数的形参总数时,才会执行)
function curry(fn) {
// 闭包
// 缓存除函数fn之外的所有参数
let args = Array.prototype.slice.call(arguments, 1)
return function() {
// 连接已缓存的老的参数和新传入的参数(即把每次传入的参数全部先保存下来,但是并不执行)
let newArgs = args.concat(Array.from(arguments))
if (newArgs.length < fn.length) {
// 累积的参数总数少于fn形参总数
// 递归传入fn和已累积的参数
return curry.call(this, fn, ...newArgs)
} else {
// 调用
return fn.apply(this, newArgs)
}
}
}
柯里化的用途
function checkByRegExp(regExp, string) {
return regExp.test(string)
}
checkByRegExp(/^1\d{10}$/, '18642838455') // 校验电话号码
checkByRegExp(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/, 'test@163.com') // 校验邮箱
我们每次进行校验的时候都需要输入一串正则,再校验同一类型的数据时,相同的正则我们需要写多次, 这就导致我们在使用的时候效率低下,并且由于 checkByRegExp 函数本身是一个工具函数并没有任何意义。此时,我们可以借助柯里化对 checkByRegExp 函数进行封装,以简化代码书写,提高代码可读性。
//进行柯里化
let _check = curry(checkByRegExp)
//生成工具函数,验证电话号码
let checkCellPhone = _check(/^1\d{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') // 校验邮箱