1. 程式人生 > >函數柯裏化

函數柯裏化

argument this 拆分 思想 [] array 性能 換來 href

1.什麽是柯裏化

柯裏化(Currying)是把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,並且返回接受余下的參數且返回結果的新函數的技術。(百度百科搜一下就有)。

從一個普通函數得到一個柯裏化函數的過程叫做函數的柯裏化,返回的函數稱為經過柯裏化的函數

函數柯裏化的技術來自於一種編程思想,就是一個復雜的問題可以通過分步的方式來求解,分步可以保證代碼邏輯的清晰易懂。

2.舉個例子

function add_1(a,b,c){//普通函數
    return a+b+c
}
console.log(add_1(1,2,3))

function add_2(a,b){//柯裏化函數
    return function(c){
        return a+b+c
    }
}
console.log(add_2(1,2)(3))

function add_3(a){//柯裏化函數
    return function(b){
        return function(c){
            return a+b+c
        }
    }
}
console.log(add_3(1)(2)(3))

function curry(func){//函數的柯裏化過程
    return function(a,b){
        return function(c){
            return func(a,b,c)
        }
    }
}

function curry2(func){//函數的柯裏化過程
    return function(a){
        return function(b){
            return function(c){
                return func(a,b,c)
            }
        }
    }
}

var add_2=curry(add_1)
var add_3=curry2(add_1)

  我們可以通過分步的return來實現參數的分步傳遞,將add_1這個普通函數變為add_2或者add_3的過程稱為函數的柯裏化。可以預見隨著傳參的不斷增加,柯裏化過程就要不斷的增加,是否可以從curry1,curry2這兩個柯裏化過程中得出一個通用的函數呢?這就是柯裏化函數的通用式。

柯裏化函數的運行過程其實是一個參數的收集過程,我們將每一次傳入的參數收集起來,最後傳給函數執行。
function add_n(func,args){//func是表示處理函數;args表示所有參數
    let length=func.length;//函數的形參個數,決定了要柯裏化的次數
    var args=args || [];//柯裏化時依次收集的參數存儲變量,包含了所有已收集的傳參

    return function(){
        let _args=Array.from(arguments);//收集柯裏化時函數參數
        [].push.apply(_args,args);//將本輪柯裏化運行時的參數添加到已收集的參數數組

        if(_args.length<length){//如果參數未收集完,即已收集的參數個數小於函數的形參個數時,遞歸調用
            return add_n.call(this,func,_args);
        }

        //當全部參數收集完成時,將所有參數傳入函數中執行
        return func.apply(this,_args)
    }
}


var test=function(a,b,c){
    return a+b+c
}

var test_curry1=add_n(test)
var test_curry2=add_n(test,[1])
test_curry1(1)(2)(3) //6
test_curry2(2)(3)   //6

  

3.實際的應用場景

理解了柯裏化的過程,就要註意柯裏化的思想更為重要,可以用來拆分邏輯。一個關於校驗的例子:

function check(partner,str){
    return partner.test(str)
}

function check_curry(partner){
    return function(str){
        return partner.test(str)
    }
}

var check_phone=check_curry(/^1[34578]\d{9}$/)
var check_email=check_curry(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/)

//使用時較為復雜難用
check(/^1[34578]\d{9}$/,‘18057192235‘)
check(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/,‘[email protected]‘)

//使用時更為清晰明了
check_phone(‘18057192235‘)
check_email(‘[email protected]‘)

  在柯裏化的實現中,我們知道柯裏化雖然具有了更多的自由度,但同時柯裏化通用式裏調用了arguments對象,使用了遞歸與閉包,因此柯裏化的自由度是以犧牲了一定的性能為代價換來的。只有在情況變得復雜時,才是柯裏化大顯身手的時候。

參考文章:https://www.jianshu.com/p/5e1899fe7d6b

  

函數柯裏化