什么是柯里化函数?

terry Javascript 266

柯里化是将具有多个参数的函数转换为每个只有一个参数的函数序列的过程。Currying 以数学家Haskell Curry 的名字命名。通过应用柯里化,n 元函数将其变成一元函数。

这样的定义不太好理解,我们可以通过下面的例子配合解释。

有一个接收三个参数的函数A。

function A(a, b, c) {
    // do something
}

假如,我们有一个已经封装好了的柯里化通用函数createCurry。他接收bar作为参数,能够将A转化为柯里化函数,返回结果就是这个被转化之后的函数。

var _A = createCurry(A);

那么_A作为createCurry运行的返回函数,他能够处理A的剩余参数。因此下面的运行结果都是等价的。

_A(1, 2, 3);
_A(1, 2)(3);
_A(1)(2, 3);
_A(1)(2)(3);
A(1, 2, 3);

函数A被createCurry转化之后得到柯里化函数_A,_A能够处理A的所有剩余参数。因此柯里化也被称为部分求值。

在简单的场景下,可以不用借助柯里化通用式来转化得到柯里化函数,我们凭借眼力自己封装。

例如有一个简单的加法函数,他能够将自身的三个参数加起来并返回计算结果。

function add(a, b, c) {
    return a + b + c;
}

那么add函数的柯里化函数_add则可以如下:

function _add(a) {
    return function(b) {
        return function(c) {
            return a + b + c;
        }
    }
}

下面的运算方式是等价的。

add(1, 2, 3);
_add(1)(2)(3);

当然,靠眼力封装的柯里化函数自由度偏低,柯里化通用式具备更加强大的能力。因此我们需要知道如何去封装这样一个柯里化的通用式。

首先通过_add可以看出,柯里化函数的运行过程其实是一个参数的收集过程,我们将每一次传入的参数收集起来,并在最里层里面处理。在实现createCurry时,可以借助这个思路来进行封装。

封装如下:

// 简单实现,参数只能从右到左传递
function createCurry(func, args) {

    var arity = func.length;
    var args = args || [];

    return function() {
        var _args = [].slice.call(arguments);
        [].push.apply(_args, args);

        // 如果参数个数小于最初的func.length,则递归调用,继续收集参数
        if (_args.length < arity) {
            return createCurry.call(this, func, _args);
        }

        // 参数收集完毕,则执行func
        return func.apply(this, _args);
    }
}

  • 暂无回复内容