一段柯里化函式程式碼閱讀

灰風GreyWind發表於2019-03-01

柯里化的概念大家應該都清楚,就是將一個接受多個引數的函式轉化為接受單一引數的函式的技術。

原始碼位於 github.com/llh911001/m…

柯里化函式:

function inspect(x) {
    return (typeof x === `function`) ? inspectFn(x) :inspectArgs(x);
}

function inspectFn(f) {
    return (f.name) ? f.name : f.toString();
}

function inspectArgs(args) {
    Array.prototype.slice.call(arguments, 0);
    return [].slice.call(args, 0).reduce(function(acc, x){
        return acc += inspect(x);
    }, `(`) + `)`;
}

function curry(fx) {
    // 函式的length屬性返回函式必須傳入的引數個數
    var arity = fx.length;

    return function f1() {
        var args = Array.prototype.slice.call(arguments, 0);
        // 引數個數滿足的處理
        if (args.length >= arity) {
            return fx.apply(null, args);
        }
        else {
        // 引數個數不滿足的處理
            var f2 = function f2() {
                var args2 = Array.prototype.slice.call(arguments, 0);
                return f1.apply(null, args.concat(args2));
            }
            f2.toString = function() {
                return inspectFn(fx) + inspectArgs(args);
            }
            return f2;
        }
    };
}
複製程式碼

其中 f2.toString 的實現是會報錯的,我已經向作者提交了PR,這段無關緊要,可以跳過不看這個 fs.toString 的實現。很顯然實現curry函式的核心就是判斷引數個數,然後各種使用apply函式。

接下來就可以體驗curry的好處:

add = curry(function(x, y) {
    return x + y;
});

const add5 = add(5);

ad5(4)
// 9
複製程式碼

這只是一個非常小的例子,原始碼還有很多例子:

add = curry(function(x, y) {
    return x + y;
});

match = curry(function(what, x) {
    return x.match(what);
});

replace = curry(function(what, replacement, x) {
    return x.replace(what, replacement);
});

filter = curry(function(f, xs) {
    return xs.filter(f);
});

map = curry(function map(f, xs) {
    return xs.map(f);
});

reduce = curry(function(f, a, xs) {
    return xs.reduce(f, a);
});

split = curry(function(what, x) {
    return x.split(what);
});

join = curry(function(what, x) {
    return x.join(what);
});
複製程式碼

在這裡我們可以看到,所有的資料引數都作為了最後一個引數,很明顯這樣在使用時的好處就在於,這可以成為一種預載入函式函式。

非常明顯的在於這樣柯里化處理函式,可以讓這些函式成為底層部署的函式。

相關文章