JavaScript 函數柯裡化的學習筆記

來源:互聯網
上載者:User

一. 函數柯裡化的定義

函數柯裡化,Function currying,又稱部分求值,指的是逐步傳參,逐步求解的過程。

二. 函數柯裡化的實現

一個Curry函數首先會接受一些參數,接受參數之後,該函數並不會立即求值,而是繼續返回另一個函數,剛才傳入的參數在函數形成的閉包中被儲存起來。待到函數被真正需要求值的時候,之前傳入的所有參數都會被一次性用於求值。

如下:

var add = (function() {
    var numArr = [];

    return function() {
        if(arguments.length === 0) {
            var result = 0;
            for(var i = 0, len = numArr.length; i < len; i++) {
                result += numArr[i];
            }
            return result;
        } else {
            // numArr.push(arguments);
            Array.prototype.push.apply(numArr, arguments);
        }
    }
})();

/* =============== 用戶端調用 =============== */
add(21);
add(2);

console.log(add()); // 23

三. 通用的柯裡化函數

柯裡化的操作可以概括為:

接受一個函數;
返回一個只接收一個參數的函數。
通用的柯裡化函數可以如下:

var currying = function(fn) {
    var args = [];

    return function() {
        if(arguments.length === 0) {
            // 進行真正的求值計算
            return fn.apply(this, args);
        } else {
            // 儲存調用的所有參數
            Array.prototype.push.apply(args, arguments);
            return arguments.callee;
        }
    }
};

那麼上面的add函數可以改寫成如下:

var add = (function() {
    var result = 0;
    return function() {
        for(var i = 0, len = arguments.length; i < len; i++) {
            result += arguments[i];
        }
        return result;
    }
})();
調用結果如下:

/* =============== 用戶端調用 =============== */
var addCurrying = currying(add); // 轉換成currying函數
addCurrying(21);
addCurrying(2);

console.log(addCurrying()); // 23

四. 反柯裡化

反柯裡化與柯裡化相反,就是把原來已經固定的參數或者this上下文等當作參數延遲到未來傳遞。

反柯裡化的作用在與擴大函數的適用性,使本來作為特定對象所擁有的功能的函數可以被任意對象所用。更通俗的解釋說反柯裡化是 函數的借用,是函數能夠接受處理其他對象,通過借用泛化、擴大了函數的使用範圍。

反柯裡化的三種寫法如下:

4.1 寫法一:

var uncurrying= function (fn) {
    return function () {
        var context = [].shift.call(arguments);
        return fn.apply(context, arguments);
    }
};

4.2 寫法二:

var uncurrying = function(fn) {
    return function() {
        return Function.prototype.call.apply(fn, arguments);
    }
}

4.3 寫法三:

var uncurrying = Function.prototype.bind.bind(Function.prototype.call);
4.4 反柯裡化的實際調用樣本:

/* =============== 用戶端調用 =============== */
var push = uncurrying(Array.prototype.push); // 反柯裡化

var arr = {};
push( arr , ["Bob" , "Jenny" , "Tom"] );

console.log(arr); // Object {0: "Bob", 1: "Jenny", 2: "Tom", length: 3}

五. 柯裡化的適用情境

當一個函數傳遞的參數絕大多數是相同的,且函數結果的可以延遲到參數耗盡時才計算,那麼該函數就適合使用柯裡化。

六. 柯裡化的效能分析

柯裡化肯定會有一些效能開銷,具體效能分析如下:

存取 arguments 對象通常要比存取具名引數要慢一些;
一些老版本的瀏覽器在 arguments.length 的實現上相當慢;
使用 fn.apply() 和 fn.call() 要比直接調用 fn() 要慢點;
建立大量嵌套範圍和閉包會帶來開銷。
七. 總結

函數柯裡化允許和鼓勵你分隔複雜功能變成更小更容易分析的部分。這些小的邏輯單元顯然是更容易理解和測試的,然後你的應用就會變成乾淨而整潔的組合,由一些小單元組成的組合。

但是函數柯裡化也會帶來一些效能開銷。在項目開發中斟酌使用。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.