Javascript 对象方式实现命名参数调用(下):自动包装偏函数

上篇,咱们实现了一个简单的函数。其可以采用灵活的多种调用方式:如下:

help({name:'john', sex:'M'});  
help("name:'john', sex:'M'");  
help('john',25);  
help(['john',25]);  

但同时带来的问题是,实现这样的一个函数,其真正的功能性代码只有一行,而为了实现上述的调用方式的支持代码却有12行。要想在自己的项目中采用这种技巧,让所有的自定义函数都拥有这样的能力肯定是一件可怕的体力活。

我们希望有这样一个东西:通过非常少的代码(最好一行),就可以把我们要调用的函数包装成一个新函数,而此新函数能支持上述的多重调用方式,最后转换为一种调用方式(命名参数调用方式)来调用我们的函数。像这样:

function helpRaw(params){ //命名参数版本  
   console.log(params.name,params.sex, param.age) ;  
}  
var help=makeSuperFunction(helpRaw, {name: "untitled" , age:18 , sex:'M' } /*默认值*/);  
help({name:'john', sex:'M'});  
help("name:'john', sex:'M'");  
help('john',25);  
help(['john',25]);  

我们就叫它 makeSuperFunction。有了它,我们甚至都不用考虑默认缺省值。可以假设传进来的参数必然完整,完全不用实现默认值逻辑。有点意思?让我们一步一步来实现它吧。

你调用或者不调用我,我就在这里。

makeSuperFunction 是一个标准的偏函数(返回函数的函数)。其返回值是一个函数,第一个参数是最终被调用的我们写的原始函数,第二个参数是此函数调用的完整default 参数对象。从功能上,很显然,makeSuperFunction 返回的函数就是根据传入的参数类型来决定调用不同方式的函数。看上去就像这样:

   var adapterFuncs = {object: makeFuncViaObject(func,defaultOption),
                        string: makeFuncViaString(func,defaultOption),
                        number: makeFuncViaParams(func,defaultOption) };
    //根据参数类型,定义不同的函数调用方式
    return function (option) {
        return adapterFuncs[typeof option](arguments);
    }

这个浅显易懂,根据传入的参数类型,返回不同的函数。这些函数又分别对应不同的调用方式。如果,大家熟悉C++,会有一种似曾相识的感觉。是不是非常像C++中的晚绑定,但是更加灵活,而且几乎没有任何限制。
所以下面,我们分别实现三个偏函数(没错,返回的函数还是一个偏函数),来分别处理三种不同的调用方式。他们是:
对象方式(包括数组方式,因为数组也是对象),字符串方式,原生的参数列表方式:

  1. 对象方式(包括数组方式):
   function makeFuncViaObject(func,defaultOption){
        return function (args){
            var option=args[0];
            if (Array.isArray(option)){//判断是否数组,如果是转换为对象
                option= _.object(_.keys(defaultOption),option);
            }
            option=_(option).defaults(defaultOption);//加入默认值
            return func(option);//调用用户函数,实现业务逻辑
        }
    }
  1. 字符串方式:
    function makeFuncViaString(func){  //support string model call
        return function(args){
            var option=args[0];
            eval("var options=[{" + option + "}]");
            return func(options);
        }
    }

然后是

  1. 参数列表方式:
    function makeFuncViaParams(func,paramNameArray){//support normal mode call
        return function (args){
            var option= _.object(paramNameArray,args);
            return func([option]);
        }
    }

好吧,我们发现。由于最终提供的函数是对象方式的调用,又没有处理默认缺省值。所以后面两种方式(字符串和参数列表方式都需要处理对象方式中的默认缺省值的代码逻辑)。既然如此,我们直接调用好了。我整理了一下上面的代码,完整的代码应该是这样的:

完整的代码

function makeSuperFunction(func,defaultOption){
    function makeFuncViaString(func){  //support string model call
        return function(args){
            var option=args[0];
            var regexp=/\\w\\s*=\\s*\\w/;
            eval("var options=[{" + option + "}]");
            return func(options);
        }
    }
    function makeFuncViaParams(func,paramNameArray){//support normal mode call
        return function (args){
            var option= _.object(paramNameArray,args);
            return func([option]);
        }
    }
    function makeFuncViaObject(func,defaultOption){//object mode support default value ; support Array
        return function (args){
            var option=args[0];
            if (Array.isArray(option)){
                option= _.object(_.keys(defaultOption),option);
            }
            option=_(option).defaults(defaultOption);
            return func(option);
        }
    }
    var adapterFuncs = {object: makeFuncViaObject(func,defaultOption),
                        string: makeFuncViaString(makeFuncViaObject(func,defaultOption)),
                        number: makeFuncViaParams(makeFuncViaObject(func,defaultOption), _.keys(defaultOption)) };
    return function (option) {
        if (option == undefined) {
            arguments[0] = option= {};
        }
        return adapterFuncs[typeof option](arguments);
    }
}

我在函数映射对象中,直接把后两种偏函数的调用目标函数包装为对象调用版本。这样,另外两个函数就不需要知道这些逻辑,直接调用即可。所有的默认缺省值支持,都交由对象方式版本来完成。
至此,我们基本已将达到了上篇所说的要求。有了上述这段代码,再加上:

function helpRaw(params){ //命名参数版本  
   console.log(params.name,params.sex, param.age) ;  
}  
var help=makeSuperFunction(helpRaw, {name: "untitled" , age:18 , sex:'M' } /*默认值*/);  
help({name:'john', sex:'M'});  
help("name:'john', sex:'M'");  
help('john',25);  
help(['john',25]); 

现在,是见证奇迹的时刻——刘谦

现在,大家终于可以完整运行一下了。然后,换一个别的函数再试试。嘿嘿。
当然,上述代码还有需要完善的地方。比如:
如果我们采用参数列表方式来调用,但第一个参数就是字符串怎么办?
这也许可以通过头尾分别加上“{”,“}”变成JSON 格式的字符串然后判断其有效性来实现。但其效率不高,而且如果这第一个参数就是合法的JSON但不包括“{}”又怎么办?
其实,在实际的工作中,字符串方式使用的非常少,其基本没有带来任何好处。而且所有可以使用字符串方式的情况都可以采用 JSON 转换为对象方式来调用。
同样道理,参数列表的第一个参数就是对象的情况也无法在上述的实现中很好的解决。至于怎么解决,这里我就不再赘述了,留待大家来研究改进吧。

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

推荐阅读更多精彩内容