JS:函式柯里化

郭佬發表於2018-12-19

函式柯里化

  1. 柯里化

    在電腦科學中,柯里化(Currying)是把接受多個引數的函式變換成接受一個單一引數(最初函式的第一個引數)的函式,並且返回接受餘下的引數且返回結果的新函式的技術。

    簡單來說,就是固定一些引數,返回一個接受剩餘引數的函式。

    其實就是使用閉包返回一個延遲執行函式。

    只看文字描述去理解柯里化可能有點難,舉一個很經典的例子:

    // 這個例子是柯里化,也可以說是部分應用
    // 對於什麼是部分應用,這裡不進行探討
    function add(num1, num2) {
        return num1 + num2;
    }
    
    function curry(func) {
        let args = [].slice.call(arguments, 1);
    
        return function() {
            let innerArgs = [].slice.call(arguments);
            let finalArgs = [...args, ...innerArgs];
            return func.apply(null, finalArgs);
        }
    }
    
    // 得到延遲執行函式
    let curriedAdd = curry(add, 5);
    // 可以多次複用得到的函式
    curriedAdd(1); // 6
    curriedAdd(2); // 7

    看了上面簡單的例子,現在來實現能這樣使用curriedAdd(1)(2, 3)(4)的柯里化函式:

    function aidCurry(func) {
        let args = [].slice.call(arguments, 1);
        return function() {
            return func.apply(null, [...args, ...arguments]);
        }
    }
    
    function curry(func, length) {
        length = length || func.length;
    
        return function() {
            // 傳入引數為 0,表示返回結果
            if (arguments.length != 0 && arguments.length < length) {
                let finalArgs = [func, ...arguments];
                // 引數的數量不足時,利用閉包將已傳入引數儲存起來
                return curry(aidCurry.apply(null, finalArgs), length - arguments.length);
            } else {
                // 引數數量夠了或者中途結束,則返回結果
                return func.apply(null, arguments);
            }
        };
    }
    
    // length 為 4,表示當傳入引數到達4個時返回結果
    let curriedAdd = curry(function add() {
        return [...arguments].reduce((acc, cur) => acc + cur);
    }, 4);
    
    // 傳入引數為4個
    curriedAdd(1)(2, 3)(4); // 10
    // 中途結束
    curriedAdd(1)(2, 3)(); // 6
    // error: not a function
    curriedAdd(1)(2)()(3); // 使用 (),就表示返回結果,已經不是函式
    curriedAdd(1)(2, 3)(4)(); // 傳入引數已經為4個,所以返回結果了,已經不是函式

相關文章