經常在面試中會有這樣的面試題:寫一個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