经常在面试中会有这样的面试题:写一个mul函数,使用方法如下:
console.loe(mul(2)(3)(4)) //output: 24
console.loe(mul(4)(3)(4)) //output: 48
实现方法:使用闭包
function mul(a) {
return function(b) {
return function(c) {
return a * b * c;
}
}
}
上面实现方法存在两方面缺陷
- 代码不够优雅,需要一层一层嵌套
- 可扩展性差,以上是3个参数,需要嵌套3层,如果有n层,需要嵌套n层
更好的解决方案:函数柯里化的实现
函数柯里化(curry)
1、函数柯里化指的是能够接收多个参数的函数转化为接收单一参数的函数,并且返回接收余下参数且返回结果的新函数的技术
2、作用和特点:参数复用,提前返回,延迟执行
以题为例
函数柯里化指的是能够接收多个参数 function multiFn(a, b, c) { return a * b * c; } 的函数通过函数合理化var multi = curry(multiFn)转化为接收单一参数multi(1)(2)(3)的函数
实现curry函数
function curry(fn, args) {
var length = fn.length;
var args = args || [];
return function(){
newArgs = args.concat(Array.prototype.slice.call(arguments));
if(newArgs.length < length){
return curry.call(this,fn,newArgs);
}else{
return fn.apply(this,newArgs);
}
}
}
调用curry函数
function multiFn(a, b, c) {
return a * b * c;
}
var multi = curry(multiFn);
multi(2)(3)(4);
以上函数只会接收3个参数,如果有n个参数,针对面试题,需要优化代码
function multi() {
var args = Array.prototype.slice.call(arguments);
var fn = function() {
var newArgs = args.concat(Array.prototype.slice.call(arguments));
return multi.apply(this, newArgs);
}
fn.toString = function() {
return args.reduce(function(a, b) {
return a * b;
})
}
return fn;
}
// 调用代码
multi(2)(3)(4) //24
multi(2)(3)(4)(5) //120
multi(1)(2)(3)(4)(5) //120
函数合成(compose)
compose 函数的作用就是组合函数,将函数串联起来执行,一个函数的输出结果是另一个函数的输入参数,一旦第 1 个函数开始执行,就会像多米诺骨牌一样推导执行了。
使用 compose 要注意以下 3 点:
- compose 的参数是函数,返回的也是一个函数。
- 除了初始函数(最右侧的一个)外,其他函数的接收参数都是一个函数的返回值,所以初始函数的参数可以是多元的,而其他函数的接收值是一元的。
- compose 函数可以接收任意的参数,所有的参数都是函数,且执行方向为自右向左。初始函数一定要放到参数的最右侧。
以上。。。
参考:【从一道面试题认识函数柯里化】https://juejin.im/post/5b8350246fb9a019c372d26d#heading-3
【详解JS函数柯里化】https://www.jianshu.com/p/2975c25e4d71
【JS函数柯里化(curry)和函数合成(compose)】http://c.biancheng.net/view/5744.html