位置:首頁 > 軟件操作教程 > 編程開發(fā) > JavaScript > 問題詳情

JavaScript 函數(shù)柯里化

提問人:劉團(tuán)圓發(fā)布時(shí)間:2020-11-25

■設(shè)計(jì)思路

    函數(shù)合成是把多個(gè)單一參數(shù)函數(shù)合成一個(gè)多參數(shù)函數(shù)的運(yùn)算。例如,a(x)和b(x)組合為a(b(x)),則合成為f(a,b,X)。注意,這里的a⑻和b(x)都只能接受一個(gè)參數(shù)。如果接受多個(gè)參數(shù),如a(x,y)和b(a,b,c),那么函數(shù)合成就會(huì)比較麻煩。

    這時(shí)就要用到函數(shù)柯里化。所謂柯里化,就是把一個(gè)多參數(shù)的函數(shù),轉(zhuǎn)化為單一參數(shù)函數(shù)。有了柯里化運(yùn)算之后,我們就能做到所有函數(shù)只接受一個(gè)參數(shù)。

【實(shí)現(xiàn)方法】

    先用傳遞給函數(shù)一部分參數(shù)來調(diào)用它,讓它返回一個(gè)函數(shù),然后再去處理剩下的參數(shù)。也就是說,把多參數(shù)的函數(shù)分解為多步操作的函數(shù),以實(shí)現(xiàn)每次調(diào)用函數(shù)時(shí),僅需要傳遞更少或單個(gè)參數(shù)。例如,下面是一個(gè)簡單的求和函數(shù)add()。

    var add = function (x, y) {

        return x + y;

    }

每次調(diào)用add(),需要同時(shí)傳入兩個(gè)參數(shù),如果希望每次僅需傳入一個(gè)參數(shù),可以這樣進(jìn)行柯里化。

    var add = function (x) {         //柯里化

        return function (y) {

            return x + y

        }

    }

    console.log(add(2)(6));          //8,連續(xù)調(diào)用

    var addl = add(200);

    console.log(addl(2));            //202,分步調(diào)用

    函數(shù)add()接受一個(gè)參數(shù),并返回一個(gè)函數(shù),這個(gè)返回的函數(shù)可以再接受一個(gè)參數(shù),并返回兩個(gè)參數(shù)之和。從某種意義上講,這是一種對參數(shù)的“緩存”,是一種非常高效的函數(shù)式運(yùn)算方法。柯里化在DOM的回調(diào)中非常有用。

■實(shí)例設(shè)計(jì)

    設(shè)想curry可以接受一個(gè)函數(shù),即原始函數(shù),返回的也是一個(gè)函數(shù),即柯里化函數(shù)。這個(gè)返回的柯里化函數(shù)在執(zhí)行的過程中,會(huì)不斷地返回一個(gè)存儲(chǔ)了傳入?yún)?shù)的函數(shù),直到觸發(fā)了原始函數(shù)執(zhí)行的條件。例如,設(shè)計(jì)一個(gè)add()函數(shù),計(jì)算兩個(gè)參數(shù)之和。

    var add = function (x, y) {

        return x + y;

    }

    柯里化函數(shù):

    var curryAdd = curry(add)

    這個(gè)add需要兩個(gè)參數(shù),但是執(zhí)行curryAdd時(shí),可以傳入更少的參數(shù),當(dāng)傳入的參數(shù)少于add需要的參數(shù)時(shí),add函數(shù)并不會(huì)執(zhí)行,curryAdd就會(huì)將這個(gè)參數(shù)記錄下來,并且返回另外一個(gè)函數(shù),這個(gè)函數(shù)可以繼續(xù)執(zhí)行傳入?yún)?shù)。如果傳入?yún)?shù)的總數(shù)等于add需要參數(shù)的總數(shù),就執(zhí)行原始參數(shù),返回想要的結(jié)果。如果沒有參數(shù)限制,最后根據(jù)空的小括號(hào)作為執(zhí)行原始參數(shù)的條件,則返回運(yùn)算結(jié)果。

【實(shí)現(xiàn)代碼】

//柯里化函數(shù) 

function curry(fn) {

    var _argLen = fn. length;                   //記錄原始函數(shù)的形參個(gè)數(shù)

    var _args = [].slice.call (arguments, 1); //把傳入的第2個(gè)及以后參數(shù)轉(zhuǎn)換為數(shù)組

    function wrap () {                         //內(nèi)部函數(shù)

        //把當(dāng)前參數(shù)轉(zhuǎn)換為數(shù)組,與前面參數(shù)進(jìn)行合并 

        _args = _args.concat([].slice.call(arguments)); 

        function act() {                //參數(shù)處理函數(shù)

            //把當(dāng)前參數(shù)轉(zhuǎn)換為數(shù)組,與前面參數(shù)進(jìn)行合并 

            —args = _args.concat([].slice.call(arguments));

            //如果傳;C參數(shù)總和大于等于原始參數(shù)的個(gè)數(shù),觸發(fā)執(zhí)行條件 

            if ( ( _argLen == 0 && arguments.length == 0) ||

                    (_argLen > 0 && _args.length >= _argLen) ) {

                    //執(zhí)行原始函數(shù),并把^次傳入?yún)?shù)傳入進(jìn)€,返回執(zhí)行結(jié)果,停止curry return fn?apply(null, _args);

            }

            return arguments.callee;

    }

    //如果傳入?yún)?shù)大于等于原始函數(shù)的參數(shù)個(gè)數(shù),即觸發(fā)了執(zhí)行條件 

    if ( (_argLen == 0 && arguments.length ==0 ) ||

           (_argLen > 0 && _args.length >= —argLen) ) {

           //執(zhí)行原始函數(shù),并把^次傳入?yún)?shù)傳入進(jìn)去,返回執(zhí)行結(jié)果,停止curry return fn.apply(null, _args);

    }

    act.toString = function () {//定義處理函數(shù)的字符串表示為原始函數(shù)的字符串表示 return fn.toString ();

    }

    return act;             //返回處理函數(shù)

    }

    return wrap;            //返回 curry 函數(shù)

【應(yīng)用代碼】

    應(yīng)用函數(shù)無形參限制。

設(shè)計(jì)求和函數(shù),沒有形參限制,柯里化函數(shù)將根據(jù)空小括號(hào)作為最后調(diào)用原始函數(shù)的條件。

//求和函數(shù),參數(shù)不限

var add= function () {//把參數(shù)轉(zhuǎn)換為數(shù)組,然后調(diào)用數(shù)組的reduce方法

    //迭代所有參數(shù)值,返回最后匯總的值

    return [].slice.call(arguments).reduce(function (a, b) {

        //如果元素的值為數(shù)值,則參與求和運(yùn)算,否則設(shè)置為0,跳過非數(shù)字的值

        return (typeof a == "number" ? a : 0) + (typeof b == "mumber" ? b : 0);

    })

}

//柯里化函數(shù)

var curried = curry(add);

console.log(curried(1)(2)(3)());           //6

var curried = curry(add);

console.log(curried(1, 2, 3)(4)());        //10

var curried = curry(add,1);

console.log(curried(1, 2)(3)(3)());        //10

var curried = curry(add,1,5);

console.log(curried(1, 2, 3, 4)(5)());     //21


應(yīng)用函數(shù)有形參限制。

設(shè)計(jì)求和函數(shù),返回3個(gè)參數(shù)之和。

var add = function (a,b,c) {            //求和函數(shù),3個(gè)參數(shù)之和

    return a + b+c;

}

//柯里化函數(shù)

var curried = curry(add,2)

console.log(curried(1)(2));            //5

var curried = curry(add,2,1)

console.log(curried(2));               //5

var curried = curry(add)

console.log(curried(1)(2)(6));         //9

var curried = curry(add)

console.log(curried(1, 2, 6));         //9

繼續(xù)查找其他問題的答案?

相關(guān)視頻回答
回復(fù)(0)
返回頂部