函数柯里化的理解和实现

什么是柯里化?

在计算机科学中,柯里化(英语:Currying),又译为卡瑞化或加里化,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

以上是维基百科对于柯里化给出的定义,总结一下:

  • 输入是一个函数,并且这个函数拥有n个参数
  • 输出也是一个函数,并且可以使用fn()()()这种方式调用
  • 参数被柯里化过程中的函数被拆分

写一个经典的用来解释柯里化的例子:

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

const addTen = curry(add, 10); // curry就是后续我们将实现的 柯里化函数
addTen(1)(2) // 13
addTen(3, 4) // 17

不难看出柯里化的用途之一就是参数复用,我们可以通过柯里化的方式很方便的实现参数复用,可能这样你感觉没啥卵用,再来看下面例子:

const amount = [
    { deposit: 120, finalPayment: 200 },
    { deposit: 110, finalPayment: 300 },
    { deposit: 130, finalPayment: 100 },
];

// 按照deposit的值对数组进行排序
// 很容易想到这么做
amount.slice().sort((a, b) => a.deposit - b.deposit);
// 后来又需要对finalPayment进行排序
amount.slice().sort((a, b) => a.finalPayment - b.finalPayment);

// 我们再来使用柯里化的形式重新写一下
const sort = curry(function(field, a, b) {
    return a[field] - b[field];
})
console.log(amount.slice().sort(sort('deposit'))); // deposit进行排序
console.log(amount.slice().sort(sort('finalPayment'))); // finalPayment进行排序

简而言之:JavaScript中的柯里化其实是利用闭包的特性,将所有参数都搜集到之后再一并执行。

function fn(a, b, c, d, e...) {}
// 通过柯里化 转换为
curryFn(a)(b)(c)(d)(e)(...)

如何实现柯里化?

对于add(a, b) {}这样的函数我们很容易柯里化它

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

function curry(fn, a) {
    return function(b) {
        return fn(a, b);
    }
}

curry(add, 10)(1); // 11

没啥毛病,那我想做一个传入三个参数的函数柯里化咋办呢?安排~

function curry(fn, a) {
    return function(b) {
        return function(c) {
            return fn(a, b, c);
        }
    }
}

那四个参数咋办呢。。。很明显这种方式并不具备通用性,其实仔细观察上面的代码,仿佛,似乎,可能递归能实现:

function curry(fn, ...args) {
    return function(...innerArgs) {
        const allArgs = [...args, ...innerArgs];
        
        if (fn.length <= allArgs.length) {
            // 说明已经接受完所有参数,这个时候可以执行了
            return fn.apply(this, allArgs);
        } else {
            // 继续返回函数,收集参数
            return curry(fn, ...allArgs);
        }
    }
}

以上就是关于柯里化的知识,希望对各位童鞋有所帮助。

你可能感兴趣的:(currying,javascript)