什么是函数柯里化

什么是“函数柯里化”

curry的概念:只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。

先看一个简单的例子,add函数接受两个参数,addcurry函数接受一个参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
// 非柯里化
function add(x, y) {
return x + y;
}
// 柯里化
function addCurry(x) {
return function(y) {
return x + y;
};
}

console.log(add(1, 2)); // 3
console.log(addCurry(1)(2)); // 3

由例子可以看出,所谓的“柯里化“就是将一个多参数的函数,转化成单参数的函数

函数柯里化的优点

  • 参数复用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // 非柯里化
    function check(reg, txt) {
    return reg.test(txt);
    }
    check(/\d+/g, 'test') //false
    check(/[a-z]+/g, 'test') //true

    // 柯里化后
    function checkCurry(reg) {
    return function(txt) {
    return reg.test(txt);
    };
    }
    const hasNumber = checkCurry(/\d+/g);
    const hasLetter = checkCurry(/[a-z]+/g);

    console.log(hasNumber('shuliqi11')); // true
    console.log(hasNumber('shuliqi')); // false
    console.log(hasLetter('1231231')); // false

    上面的示例是一个正则的校验,正常来说直接调用check函数就可以了,但是如果我有很多地方都要校验是否有数字,其实就是需要将第一个参数reg进行复用,这样别的地方就能够直接调用hasNumber,hasLetter等函数,让参数能够复用,调用起来也更方便

  • 延迟运行

    1
    2
    3
    4
    5
    6
    7
    8
    Function.prototype.bind = function (context) {
    var _this = this
    var args = Array.prototype.slice.call(arguments, 1)

    return function() {
    return _this.apply(context, args)
    }
    }

    像我们js中经常使用的bind,实现的机制就是Curry

如何实现柯里化

我们先看一个例子:这里使用了(ramda, 自行安装)。

1
2
3
4
5
6
7
8
9
10
11
var _ = require("ramda");

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

var curry_add = _.curry(add);

console.log(curry_add(1)); // 输出函数
console.log(curry_add(1)(2)); // 输出函数
console.log(curry_add(1)(2)(3)); // 输出结果

栗子中我们对 add 进行了柯里化,从结果上可以看到当参数为 1 个时返回的是个函数,当参数为 2 个的时候返回函数,当参数为 3 个的时候返回函数执行结果

根据上述的小栗子,可以得到,柯里化后的函数如果接受到全部参数则返回函数执行结果,否则返回一个柯里化函数

1
2
3
4
5
6
7
function curry(fn) {
return function() {
// 假如我们柯里化的函数叫 curry_fn
// if curry_fn接收到的参数等于fn接受
// else return "一个柯里化函数"
}
}

上述伪代码是不是很像递归?

  • 递归出口:curry_fn接受到的参数数量等于fn接受参数的数量
  • 重复逻辑:return “一个柯里化函数”

于是有了以下简单实现柯里化的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function curry(fn, args = []) {
return function() {
const rest = [...args, ...arguments];
if (rest.length < fn.length) {
// 如果传入的参数的个数没有等于 fn 函数的参数的个数,则递归返回
return curry.call(this, fn, rest);
}
else {
// 执行fn
return fn.apply(fn, rest);
}
}
}
function add(x, y, z) {
console.log(x + y + z);
}
var curryAdd = curry(add);
console.log(curryAdd(1)(1)(1)); // 3
文章作者: 舒小琦
文章链接: https://shuliqi.github.io/2018/10/05/什么是函数柯里化/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 舒小琦的Blog