函数科里化是函数可以先接收一个参数,返回新函数,新函数接收剩余参数。
先写个例子感受下科里化。
let add = function(a,b){ //原函数
console.log(a+b)
}
function curry(a){
return function(b){
console.log(a+b)
}
}
let add1 = curry(1)
let add2 = curry(2)
add1(1) //2 等价于 add(1,1)
add2(1) //3 等价于 add(2,1)
如果经常+1,就可以先传入1,然后直接调用add1,而不是每次都是给add函数传参数1。虽然例子简单,没必要科里化。但是还是能看出有点:科里化简化了传参,并且提高了函数复用性。
再举个例子吧:
function check( reg, targetString) { //原函数
console.log(reg.test(targetString));
}
function curryCheck(reg){
return function(targetString){
console.log(reg.test(targetString));
}
}
// 用来验证电话号
let checkPhone = curryCheck(/^1[34578]\d{9}$/)
// 用来验证邮箱
let checkEmail = curryCheck(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/)
checkPhone('11111111111')
checkEmail('1111111@qq.com')
// 等价于原函数
check(/^1[34578]\d{9}$/,'11111111111')
check(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/,'1111111@qq.com')
check函数每次必须传两个参数,如果多处验证手机号,那么第一个参数就会重复的传,使用起来麻烦。科里化之后,使用起来更方便直观了。
当我们要对不同函数进行科里化时,我们就该意识到需要封装个函数科里化的方法了。在进行查阅借鉴后,找到了个比较容易理解的版本。
function curry(func, ...args) {
let length = func.length // 记下原函数参数个数
let all = args || []; // 目前传入的所有参数
return function (...rest) {
let _args = all.slice(0); // 拷贝新的all,防止改变了公共的all
_args.push(...rest) // 将后面传入的参数加入拷贝的all中
if (_args.length < length) { // 如果目前参数不够,继续收集
return curry.call(this, func, ..._args) // 保存目前参数的_args会赋值给all
} else { // 目前参数够了,执行
return func.apply(this, _args)
}
}
}
封装完后我们来简单应用下:
function add(x, y, z) {
console.log(x + y + z)
}
let curryAdd = curry(add)
curryAdd(1)(2)(3) //6
curryAdd(1,2)(3) //6
let add1 = curry(add,1)
add1(2)(3) //6
add1(2,3) //6
封装科里化的核心思想就是 收集参数 ,当参数够了的时候,执行。