函數柯里化
理解: 指的是將一個接受多個參數的函數 變為 接受一個參數返回一個函數的固定形式,這樣便於再次調用,例如f(1)(2)
例如 常見的add函數
function add(a,b){
return a+b
}
// 變為
function curry(fn){
var firstArgs=Array.prototype.slice.call(arguments,1) //這里,arguments的第一個參數是fn,所以從1開始
var _cur=function(){
var nextArgs=[...arguments]
var allArgs=firstArgs.concat(nextArgs)
return fn.apply(this,allArgs)
}
return _cur
}
var add1=curry(add,10)
add1(10) //20
add1(20) //30
當前的柯里化curry接收一個函數,並且返回一個函數用於處理剩下的參數,因此可以連續兩次調用,即curr(add,10)(20) 返回30
難度升級
此時一個簡單的柯里化完成,但是如果遇到f(1)(2)(3)...等連續調用多次的時候,則會顯得無力,此時需要一個更加復雜的柯里化,遞歸柯里化
function add(){
return [].reduce.call(arguments,(a,b)=>{
return a+b
},0)
}
function curry(fn){
var len=fn.length // fn.length 指的是函數需要接受的參數長度
var args=Array.prototype.slice.call(arguments,1)
var _adder= function(){
var _args=Array.prototype.slice.call(arguments) // 等價於arguments.slice()
if(_args.length==0){
return fn.apply(this,args)
}else{
[].push.call(args,..._args)
return _adder
}
}
_adder.toString=function(){
return _adder()
}
return _adder
}
var add1=curry(add)
console.log(add1(2)(2).toString()) //4
注意:call和apply的區別
- 兩者都是改變函數的this指針,如果第一個參數為null或者undefined則默認指向 window
- 不同的是call接收的第二個參數是 所有的實參,而apply接收的是一個數組
- 例如 fn.call(obj,1,2,3) fn.apply(obj,[1,2,3])
練習
實現一個函數,使得其能完成如下功能
add(1) //1
add(1)(2) //3
add(1)(1,2,3) //7
function add(){
var args=[...arguments]
var _adder= function(){
var _args=Array.prototype.slice.call(arguments)
if(_args.length==0){
return args.reduce((a,b)=>{
return a+b
},0)
}else{
[].push.call(args,..._args)
return _adder
}
}
_adder.toString=function(){
return _adder()
}
return _adder
}