转载:js函数柯里化

百度百科对柯里化的解释:在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。这个技术由 Christopher Strachey 以逻辑学家 Haskell Curry 命名的,尽管它是 Moses Schnfinkel 和 Gottlob Frege 发明的。
相信没有几个人在看了上面这段解释之后能立马理解函数柯里化是什么东西。通俗一点讲,函数柯里化的主要目的就是为了减少函数传参,同时将一些固定参数私有化。下面展示一段非常简单计算圆面积的代码来说明函数柯里化的原理:

//circle函数,接受半径r和π
function circle(r,p){
    //计算半径为r的圆的面积
    var area=p*r*r;
    return area;
}
/*
 * 通过函数柯里化来简化circle函数,只传入半径就能计算出面积
 * 不管怎么样,π是不会变的,因此我们将他写死,不需要外部调用传入
 */
function curryCircle(r){
    var p=3.14;
    var area=p*r*r;
    return area;
}

也许你会觉得这段代码很二,但是这就是函数柯里化的真实面目。当然上面的代码只是一个非常小的例子,真实世界中的函数柯里化会比它凶恶一点,下面来讨论一个更通用的例子。假设π不是唯一的(比如我们有三种π),我们计算圆面积公式当中的π会根据场景不同而变化,这个时候我们就不能直接写死,而需要根据不同环境来配置π:

//circle函数,接受半径r和π
function circle(r,p){
    //计算半径为r的圆的面积
    var area=p*r*r;
    return area;
}
//针对circle函数的柯里化函数
function curry(fn,p){
    var finalMethod=function(r){
        var result=fn(r,p);
        return result;
    }
    return finalMethod;
}
//我们有3种不同的π
var curryCircle1=curry(circle,1.14);
var curryCircle2=curry(circle,2.14);
var curryCircle3=curry(circle,3.14);
//输出:4.56  8.56  12.56
console.log(curryCircle1(2),curryCircle2(2),curryCircle3(2));

可以看到,curry方法通过封装最基础的circle方法,同时保存设置好的p参数(π),并返回一个finalMethod方法,这样我们最终调用finalMethod时就只需要传入参数r(半径)就可以完成。借助函数柯里化,我们拥有了三个简化的计算圆面积方法。上面展示的函数柯里化只能适用于圆面积的计算,这次我们编写一个更通用的柯里化函数:

function curry(fn){
    //第一个参数是基础执行方法,slice切除
    var args=Array.prototype.slice.call(arguments,1);
    //直接返回匿名函数
    return function(){
        //slice新参数以便能调用concat
        var innerArgs=Array.prototype.slice.call(arguments);
        //将配置的参数和新传入的参数合并
        var finalArgs=args.concat(innerArgs);
        return fn.apply(null,finalArgs);
    };
}

curry()函数的主要工作就是将被返回函数的参数进行排序。Curry()的第一个参数是要进行柯里化的函数,其他参数是要传入的值。为了获取第一个参数之后的所有参数,在arguments对象上调用了slice()方法,并传入参数1表示被返回的数组包含从第二个参数开始的所有参数。然后args数组包含了来自外部函数的参数。在内部函数中,创建了innerArgs数组用来存放所有传入的参数(又一次使用了slice())。有了存放来自外部函数和内部函数的参数数组后,就可以使用concat()方法将他们合并成finalArgs。最后使用apply()将结果传递给该函数。这样就实现了一个通用的函数柯里化。如果到这此还有余力的读者可以接着往下看,我们将要介绍jQuery中使用的函数柯里化。
在针对某个方法进行柯里化时,我们甚至不用传入fn来告诉柯里化来包装我们的函数,我们可以通过原型直接将函数和柯里化绑定:

Function.prototype.curry=function(){
    //利用原型的便利,我们可以直接通过this引用到方法
    var fn=this;
    var args=Array.prototype.slice.call(arguments);
    return function(){
        var arg=0;
        //循环校验先前传入的参数和新传入的参数是否有差别
        for(var i=0;i<args.length && arg<arguments.length;i++){
            if(args[i]===undefined){
                args[i]=arguments[arg++];
            }
        }
        return fn.apply(this,args);
    };
};

与之前不同,我们通过this引用获取了方法引用,这样当我们需要将某个函数柯里化时,只要这样写就可以:

var delay=setTimeout.curry(undefined,10);

delay就是一个已经被提前设定了10毫秒延迟的setTimeout函数。我们仍然通过args来保存参数配置,不过这次有点区别:在for循环内部会校验args和arguments的区别,以此判断来完成参数拼接。所以传给curry的参数必须是完整参数(即意味着不传的值要传入undefined)。最终我们实现了一个不需要传入fn的柯里化方法。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,907评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,546评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,705评论 0 238
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,624评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,940评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,371评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,672评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,396评论 0 195
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,069评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,350评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,876评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,243评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,847评论 3 231
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,004评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,755评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,378评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,266评论 2 259

推荐阅读更多精彩内容