什么是柯理化函数?
柯理化函数实践
1.先举个例子
1.定义一个add函数 用于计算两数之和
function add(x,y) {
return x+y
}
2. 编写一个curry函数 用来执行add函数
function curry(fn) {
// 首先获取调用curry函数 传入的参数并保存 (闭包)
var args = [].slice.call(arguments, 1)
return function() {
// 获取调用新函数传入的参数
var newArgs = [].slice.call(arguments)
// 最后调用add 函数
fn.apply(this, args.concat(newArgs))
}
}
3. 测试
var addCurry = curry(add,1,2);
addCurry(); //3
//或者
var addCurry = curry(add,1);
addCurry(2); //3
//或者
var addCurry = curry(add);
addCurry(1, 2) // 3
你以为这就是柯理化了么? 远远不够!!!
什么是柯理化? 柯理化是每次调用函数只传递一个参数 类似curry(1)(2) 就能得到结果。
显而易见 ! 我们还需要对此函数进行改进。
比如说add这个函数接受两个参数,那么针对柯理化之后的函数,若传入的参数没有到达两个的话,就继续调用curry,继续接受参数。若参数到达2个了,就直接调用add函数。
function add(x,y) {
return x+y
}
function curry(fn,args) {
//根据这个思路 我们首先就要获取add函数的参数
let length = fn.length,
args = args || []
return function() {
newArgs = args.concat([].slice.call(arguments))
if(newArgs.length < length) {
// 递归 继续获取参数 继续执行curry
return curry.call(this, fn, newArgs)
} else {
return fn.apply(this, newArgs)
}
}
}
// 测试
var addCurry = curry(add);
addCurry(1,2) //3
addCurry(1)(2) //3
但这一版柯理化仍不能达到高可复用性的要求: 因为它只能实现有特定参数个数的函数适用。
假如有这样一个需求:
//实现一个add方法,使计算结果能够满足如下预期:
add(1)(2)(3) = 6
add(1, 2, 3)(4) = 10
add(1)(2)(3)(4)(5) = 15
我们之前写的柯里化是不能满足这个需求的,因为传入的参数个数是不固定的。
其实这里的需求是我们在柯里化的过程中既能返回一个函数继续接受剩下的参数,又能就此输出当前的一个结果。
这里就需要使用函数的toString来完成。
当我们返回函数的时候,会调用函数的toString来完成隐式转换,这样输出的就不是函数的字符串形式而是我们定义的toString返回的值。这样就既可以保持返回一个函数,又能够得到一个特定的值。
function add() {
// 收集参数
var _args = Array.prototype.slice(arguments)
// 创建一个内部函数 利用闭包收集所有参数
var _adder = function() {
_args.push(...arguments)
return _adder
}
// 利用toString隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回
_adder.toString = function() {
_args.reduce((a,b) => a + b)
}
return _adder
}
//测试
add(1)(2)(3) // 6
add(1, 2, 3)(4) // 10
add(1)(2)(3)(4)(5) // 15
add(2, 6)(1) // 9
2.柯理化的好处
// 正常的正则校验
function check(reg, txt){
return reg.text(txt)
}
// 调用
check(/\d+/g, 'test') // false
check(/[a-z]+/g, 'test') // true
// 柯理化后
function curryingCheck(reg){
return function (txt) {
return reg.text(txt)
}
}
// 校验数字方法
var hasNumber = curryingCheck(/\d+/g)
// 校验英文
var hasLetter = curryingCheck(/[a-z]+/g)
hasNumber('text1') // true
hasNumber('txtste') // false
hasLetter('2122') // true