This article is about the mathematical technique. For the cooking process of this name, see Curry. For the leather finishing process, see Currier.
In mathematics and computer science, currying is the technique of translating the evaluation of a function that takes multiple arguments (or a tuple of arguments) into evaluating a sequence of functions, each with a single argument. Currying is related to, but not the same as, partial application.

(维基百科)
从维基百科了解的:
柯里化(英语:Currying),又译为卡瑞化或加里化,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
顾名思义,柯里化其实本身是固定一个可以预期的参数,并返回一个特定的函数,处理批特定的需求。这增加了函数的适用性,但同时也降低了函数的适用范围。
怎么办还是无法理解,那我们就来按照它的定义去柯里化一个代码:
首先我们 做一个1+b+c+d的 接受多个参数的函数

1
2
3
4
function count(b,c,d){
return 1+b+c+d;
}
count(2,3,4);

其次将我们将上诉函数重写为一个单一参数并且返回接受余下的参数而且返回结果的新函数

1
2
3
4
5
6
7
8
9
10
11
12
13
function add(x){
var arr = [];
var tem = function(x){
if(x===undefined){
return arr.reduce(function (preValue,curValue) { return preValue + curValue; })
}else {
arr.push(x);
return tem;
}
}
return tem(x);
}
add(2)(3)(4)();

而柯里化函数,是以1中的函数为参数,通过本函数转化为2中的一个新函数的技术,并不改变一中的函数,也就是说柯里化不是追求最终的计算结果,而是简化求值的方法,转化函数的一个技术。这就是 把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数涵义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//柯里化方法
function currying (fn){
var arr = [1];
return function(x){
if(x===undefined){ //求值
return fn.apply(null,arr)
}else {
arr.push(x);
return arguments.callee;
}
}
}
//参数函数
function count(){
return [].reduce.call(arguments,function(a,b){return a+b;});
}
//柯里化后的新方法,也就是2中的方法
var add = currying(count);
add(2)(3)(4)();

上诉就是从科里化的定义来解释并实现化的过程,柯里化的实用性体现在很多方面,它主要有三大特性

  1. 部分参数复用/固定易变因素
    bind方法就是一个典型的固定易变因素科里化方法;

    1
    2
    3
    4
    5
    6
    7
    Function.prototype.bind = funciton(content){
    var _this = this,
    args = [].slice.call(arguments,1);
    return function(){
    _this.apply(content,args);
    }
    }
  2. 延时加载 上诉科里化的定义来解释并实现第三计算add(2)(3)(4) 就是延时加载。
    延时加载是利用闭包内存可保存的特性,可以让你的设计具有一定惰性 而是非优化性能,从占用内存程度来说,延时加载比直接得到结果性能更差一些。但它是Curry 的核心思想,就是把多参数传入的函数拆成单参数(或部分)函数,内部再返回调用下一个单参数(或部分)函数,依次处理剩余的参数。
    一般与[函数式编程]相辅相成。

  1. 提高通用性,代码可高度复用
    解决了兼容性问题,但同时也会再来,使用的不便利性,不同的应用场景往,要传递很多参数,以达到解决特定问题的目的。有时候应用中,同一种规则可能会反复使用,这就可能会造成代码的重复性
    看以下例子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    function square(i) {
    return i * i;
    }
    function dubble(i) {
    return i *= 2;
    }
    function map(handeler, list) { 
    return list.map(handeler);
    }
    // 数组的每一项平方
    map(square, [1, 2, 3, 4, 5]);
    map(square, [6, 7, 8, 9, 10]);
    map(square, [10, 20, 30, 40, 50]);
    // ......
    // 数组的每一项加倍
    map(dubble, [1, 2, 3, 4, 5]);
    map(dubble, [6, 7, 8, 9, 10]);
    map(dubble, [10, 20, 30, 40, 50]);

    看下面,我们利用柯里化改造一下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    function square(i) {
    return i * i;
    }
    function dubble(i) {
    return i *= 2;
    }
    function map(handeler, list) {
    return list.map(handeler);
    }
    function currying(fn,fn2) {
    return function(list){
    return fn.apply(null,fn2,list);
    }
    }
    var mapSQ = currying(map, square);
    mapSQ([1, 2, 3, 4, 5]);
    mapSQ([6, 7, 8, 9, 10]);
    mapSQ([10, 20, 30, 40, 50]);
    var mapDB = currying(map, dubble);
    mapDB([1, 2, 3, 4, 5]);
    mapDB([6, 7, 8, 9, 10]);
    mapDB([10, 20, 30, 40, 50]);

    为什么使用克里化

    在我看来,它有 2 大优势

  2. 程序片段越小越容易被配置
  3. 尽可能地函数化

    支配

    由于克里化的延时执行的特性,将一个大的程序分割成N个小程序执行,这样你可以精确的设计,改变每一步执行的程序,让你对整体的把控更加细致。
    举个显而易见的例子,获取集合每个成员的 id :

    1
    2
    var objects = [{id:1},{id:2},{id:3},{id:4}];
    objects.map(function(o){ return o.id });

    map函数,他做了什么:

    1
    2
    3
    4
    5
    6
    7
    Array.prototype.map = function(fn){
    var arr = [],
    _this = this;
    for(var i = 0;i<_this.length;i++;){
    arr.push(fn(_this[i],i))
    }
    }

    现在我们用curry去转换map的参数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    var objects = [{id:1},{id:2},{id:3},{id:4}];
    function curry(fn){
    var args = [];
    return function(x){
    if (typeof x==='undefined'){
    return fn.apply(null,args);
    }else{
    args.push(x);
    return arguments.callee;
    }
    }
    }
    var get = curry(function(key,obj){
    return obj[key];
    })
    var map = curry(function(fn,arr){
    return arr.map(fn)
    })
    var getIds = map(get('id'));
    getIds(objects)() //= [1, 2, 3]

    这样我们就能通过传入一个函数,对数组的每一项去做一个精细的处理

    尽可能地函数化

    首先我们得知道什么是函数式,简单来说:
    函数式:将我们需用的的函数通过克里化的技术进行函数合成形成一个函数通道,根据传入的值的不同而得到对应不同值的一种编程思想,具体详见[从函数式编程分析redux与vuex]
    显而易见,克里化本来就是将一个函数作为参数得到另外一个函数的技术,而这个过程就是函数化:

    反克里化

    如果说克里化是
    ###