函数柯里化
前言
在js中,其实有许多的方法能让你的函数变得更加灵活,感觉上就如同成为一个新的函数一样,特别有意思,也特别好用,这次就来介绍一种能让参数固定的方式,函数柯里化 (๑•̀ㅂ•́)و✧
代码实例
function a(a,b){
return a+b
}
var q= curry(a);
console.log(q(10,12));//22
var q2=q(1);
console.log(q2(3)) //4
console.log(q2(-4)) //-3
从上面的这段代码中,可以看到 a方法经过curry方法后,返回了个函数,此时可以执行分开传值的操作,也可以进行一次全部传参直接执行的操作,感觉是不是很有意思 d=====( ̄▽ ̄*)b
相对于直接传入参数的形式来讲,这种形式能让你的函数灵活组合,而不必反复的去引用传参
以下是一个建议版本的两段式柯里化实现
function curry(fn) {
return function () {
var arg = [].slice.apply(arguments);
if(fn.length ==arguments.length) return fn.apply(fn,arg);
return function(){
return fn.apply(fn,arg.concat([].slice.apply(arguments)))
}
}
}
我们可以看到,curry函数会将传入的function保存起来,在第一段的时候进行传入参数个数的判定,如果够了就直接执行,不够的话,保留本次的参数,再次返回一个函数
实例优化
从上面的代码中我们可以明显的看到,二段式的柯里化还是有许多的局限性的,例如想成三段,或者传入对象,都会有bug,那么接下来我们就来优化一下function curry2(f, arg) {
var arg = arg || [],
isTrue = typeof arguments[arguments.length - 1] === "boolean" ?
[].slice.apply(arguments).pop() : true;
return function () {
var newArg = isTrue ?
JSON.parse(JSON.stringify(arg.concat([].slice.apply(arguments)))) :
arg.concat([].slice.apply(arguments));
return f.length <= newArg.length ? f.apply(f, newArg) :
curry2.call(this, f, newArg, isTrue);
}
}
var c = {}
var a2 = curry2(a, [])
var a3 = a2(c)
a3(3, c) //{name: "my"} 3 {};
var a2 = curry2(a, []);
var a3 = a2(c);
a3(3, c);//{name: "my"} ; {name: "my"}
经过此次优化后,我们可以看到,传入对象后,我们同样的可以选择修改或不修改原来的对象,选择true或不传第三参的话,我们的柯里化函数更加符合函数式编程中,去除副作用的思维方式,传参的话,用在面向对象的模式中会好许多
实际使用
在实际的使用层面来讲,简单举几个例子,例如将url分开组装,axios中可以对需要重复发送请求的的url进行柯里化,亦或者在vue中,我们可以对methodes中专门控制动画或者渲染的方法进行柯里化传参,达到不同的动画效果,还有在react中,函数返回一个组件的时候,我们可以对其传入的参数进行一个固定,达到不同的效果
当然,开发一个小型代码库的时候,同样可以在内部使用这些方式来对代码进行优化滴(o゚v゚)ノ