# 柯里化
# 什么是柯里化
柯里化指这样的一种函数,它接受一个函数A为参数,返回一个新的函数,新函数能够接受函数A的剩余参数。
# 举例实现柯里化
var add = (a,b,c) => a+b+c
var _add = curry(add)
假设我们有一个函数curry,有一个函数add,通过curry返回新函数_add。
柯里化使得我们可以这样传参:
_add(1)(2)(3)
_add(1)(2,3)
_add(1,2)(3)
来实现一下这个curry函数:
function createCurry(fn) {
var fn_len = fn.length; // 获取原函数参数个数
var args = Array.prototype.slice.call(arguments, 1); // 已传入参数,通过闭包保存
return function() {
var _args = Array.prototype.slice.call(arguments);
_args = args.concat(_args)
// 参数个数不够则递归
if (_args.length < fn_len) {
return createCurry(fn, ..._args);
}
// 参数达标
return fn(..._args);
}
}
通过Function.length (opens new window)获取原函数的形参个数, 通过闭包保存剩余参数,返回一个新的函数,拼接闭包中的参数和新函数的参数,对比原函数的形参个数,参数不足递归继续生成另一个新函数来收集参数,参数达标则调用原函数并传入所有参数。
稍微优化一下可以这样写,增加了一个原函数无入参的判断:
function curry(fn) {
if(fn.length<=1) return fn; // 原函数无入参,直接返回原函数
var args = Array.prototype.slice.call(arguments, 1);
return function() {
var _args = args.concat(Array.prototype.slice.call(arguments));
return _args.length < fn.length ? createCurry(fn, ..._args) : fn(..._args);
}
}
var add = (a,b,c) => a+b+c
var _add = curry(add)
var result1 = _add(1)(2,3)
console.log(result1) // 6
var result2 = _add(2)(3)(4)
console.log(result2) // 9
# 应用场景
通过上面的例子我们已经能够简单的实现柯里化,但还是不知道为什么要这样做,为什么要把参数分开传递,来看一下下面两个应用场景。
# 场景一:正则校验
当我们需要用正则来校验手机号时,可能会这样写:
function checkPhone(phone) {
return /^1[34578]\d{9}$/.test(phone);
}
如果我们还需要一个邮箱验证,那就又要写一个函数
function checkEmail(email) {
return /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test(email);
}
如果还需要验证身份证、验证车牌号、验证...那就要写很多很多个这样的函数,而他们唯一的区别就是正则表达式的不同。
我们确实可以写一个这样的函数:
function checkFun(reg,val) {
return reg.test(val)
}
checkFun(/^1[34578]\d{9}$/,'13111111111')
checkFun(/^1[34578]\d{9}$/,'13122221111')
checkFun(/^1[34578]\d{9}$/,'13133331111')
但是我们每验证一个新的手机号,就要传一次这样的正则。
如果我们使用柯里化的思想,就可以这样写:
function getCheckFun(reg) {
return function(val){
return reg.test(val)
}
}
var phoneCheck = getCheckFun(/^1[34578]\d{9}$/);
console.log(phoneCheck('13111111111'))
console.log(phoneCheck('13122221111'))
var emailCheck = getCheckFun(/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/);
emailCheck('aa@fe.123.cn')
emailCheck('bb@fe.123.cn')
# 场景二:类型判断
var isType = type => target => `[object ${type}]` === Object.prototype.toString.call(target)
来理解一下这个isType函数,接受一个type入参,返回一个新函数,这个新函数接受一个target入参,返回类型判断结果。
使用起来式这样的:
var isArray = isType('Array');
var isObject = isType('Object');
var isString = isType('String');
console.log(isArray([])) // true
console.log(isArray(1)) // false
console.log(isObject({})) // true
console.log(isObject(2)) // false
console.log(isString('')) // true
console.log(isString(3)) // false