JavaScript 通过模式匹配实现重载

 更新时间:2010年08月12日 10:19:12   作者:  
昨天rank同学向我提出一个问题,在实际应用中有些接口需要提供类似于函数重载的功能,以方便开发者组织代码逻辑,简化使用者调用。
正好infinte同学提出“更优雅的兼容”其实也和这个问题有一定的关联(我们后面会看到)

在youa的脚本库中Function的Helper中,添加支持重载的模式匹配
复制代码 代码如下:

/**
* 函数参数重载方法 overload,对函数参数进行模式匹配。默认的dispatcher支持*和...以及?,"*"表示一个任意类型的参数,"..."表示多个任意类型的参数,"?"一般用在",?..."表示0个或任意多个参数
* @method overload
* @static
* @optional {dispatcher} 用来匹配参数负责派发的函数
* @param {func_maps} 根据匹配接受调用的函数列表
* @return {function} 已重载化的函数
*/
overload: function(dispatcher, func_maps) {
if (! (dispatcher instanceof Function)) {
func_maps = dispatcher;
dispatcher = function(args) {
var ret = [];
return map(args, function(o) {return getType(o)}).join();
}
}

return function() {
var key = dispatcher([].slice.apply(arguments));
for (var i in func_maps) {
var pattern = new RegExp("^" + i.replace("*", "[^,]*").replace("...", ".*") + "$");
if (pattern.test(key)) {
return func_maps[i].apply(this, arguments);
}
}
};
},

FunctionH.overload 包括两个参数,一个是负责处理匹配条件的dispatcher函数(可缺省),另一个是一组函数映射表,默认dispatcher函数是根据实际调用的参数类型生成一个字符串,例如调用的三个参数依次为10、”a”、[1,2]将生成”number,string,array”,具体实现模式匹配的时候,将根据函数映射表的每一个”key”生成一个正则表达式,用这个正则表达式匹配dispatcher函数的返回值,如果匹配,则调用这个key对应的处理函数,否则依次匹配下一个key,例如:
复制代码 代码如下:

getEx: function(obj, prop, returnJson) {
var ret, propType = ObjectH.getType(prop);
if (propType == 'array') {
if (returnJson) {
ret = {};
for (var i = 0; i & lt; prop.length; i++) {
ret[prop[i]] = ObjectH.getEx(obj, prop[i]);
}
} else {
//getEx(obj, props)
ret = [];
for (var i = 0; i & lt; prop.length; i++) {
ret[i] = ObjectH.getEx(obj, prop[i]);
}
}
} else {
//getEx(obj, prop)
var keys = (prop + "").split(".");
ret = obj;
for (var i = 0; i & lt; keys.length; i++) {
ret = ret[keys[i]];
}
if (returnJson) {
var json = {};
json[prop] = ret;
return json;
}
}
return ret;
},

上面这种情况下“万恶”的 if 可以优化为:
复制代码 代码如下:

getEx: FunctionH.overload({
"*,array,*": function(obj, prop, returnJson) {
if (returnJson) {
ret = {};
for (var i = 0; i & lt; prop.length; i++) {
ret[prop[i]] = ObjectH.getEx(obj, prop[i]);
}
} else {
ret = [];
for (var i = 0; i & lt; prop.length; i++) {
ret[i] = ObjectH.getEx(obj, prop[i]);
}
}
return ret;
},
"*,string,*": function(obj, prop, returnJson) {
var keys = (prop + "").split(".");
ret = obj;
for (var i = 0; i & lt; keys.length; i++) {
ret = ret[keys[i]];
}
if (returnJson) {
var json = {};
json[prop] = ret;
return json;
}
return ret;
}
}),

OK,这种形式在一些人看来或许已经比原来看起来好一些了,但是其实还可以更进一步的——
复制代码 代码如下:

getEx: FunctionH.overload(function(args) {
return "prop is " + ObjectH.getType(args[1]);
},{
"prop is array": function(obj, prop, returnJson) {
if (returnJson) {
ret = {};
for (var i = 0; i & lt; prop.length; i++) {
ret[prop[i]] = ObjectH.getEx(obj, prop[i]);
}
} else {
//getEx(obj, props)
ret = [];
for (var i = 0; i & lt; prop.length; i++) {
ret[i] = ObjectH.getEx(obj, prop[i]);
}
}
return ret;
},
"prop is string": function(obj, prop, returnJson) {
var keys = (prop + "").split(".");
ret = obj;
for (var i = 0; i & lt; keys.length; i++) {
ret = ret[keys[i]];
}
if (returnJson) {
var json = {};
json[prop] = ret;
return json;
}
return ret;
}
}),

还有“讨厌”的第三个参数,干脆也一并处理了——
复制代码 代码如下:

getEx: FunctionH.overload(function(args) {
return "prop is " + ObjectH.getType(args[1]) + " and returnJson is " +args[2];
},{
"prop is array and returnJson is true": function(obj, prop, returnJson) {
ret = {};
for (var i = 0; i & lt; prop.length; i++) {
ret[prop[i]] = ObjectH.getEx(obj, prop[i]);
}
return ret;
},
"prop is array and returnJson is false": function(obj, prop, returnJson) {
ret = [];
for (var i = 0; i & lt; prop.length; i++) {
ret[i] = ObjectH.getEx(obj, prop[i]);
}
return ret;
},
"prop is string and returnJson is true": function(obj, prop, returnJson) {
var keys = (prop + "").split(".");
ret = obj;
for (var i = 0; i & lt; keys.length; i++) {
ret = ret[keys[i]];
}
var json = {};
json[prop] = ret;
return json;
},
"prop is string and returnJson is false": function(obj, prop, returnJson) {
var keys = (prop + "").split(".");
ret = obj;
for (var i = 0; i & lt; keys.length; i++) {
ret = ret[keys[i]];
}
return ret;
}
}),

例如说浏览器嗅探和特性探测之类种种,同理也能采用这个模式(当然这种形式有利有弊,使用者自己权衡吧)——
复制代码 代码如下:

foo = FunctionH.overload(function() {
return MSIE ? "IE": "NotIE";
},{
"IE": function() {...}
"NotIE": function() {...}
});

相关文章

  • JavaScript中如何判断一个值的类型

    JavaScript中如何判断一个值的类型

    在js中有一个运算符可以帮助我们判断一个值的类型,它就是typeof运算符。下面通过本文给大家分享JavaScript中如何判断一个值的类型,需要的朋友参考下吧
    2017-09-09
  • JS URL传中文参数引发的乱码问题

    JS URL传中文参数引发的乱码问题

    今天的项目中碰到了一个乱码问题,从JS里传URL到服务器,URL中有中文参数,服务器里读出的中文参数来的全是“?”,查了网上JS编码相关资料得以解决。
    2009-09-09
  • 基于JavaScript实现生成名片、链接等二维码

    基于JavaScript实现生成名片、链接等二维码

    本文使用javascript技术实现生成名片、链接等二维码的代码,代码简单易懂并附有注释,需要的朋友可以参考下本文
    2015-09-09
  • 解决window.open()被浏览器拦截的问题

    解决window.open()被浏览器拦截的问题

    这篇文章介绍了window.open()被浏览器拦截的解决方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-06-06
  • 关于javascript中json 对象数组之间相互转化问题

    关于javascript中json 对象数组之间相互转化问题

    这篇文章主要介绍了关于javascript中json 对象数组之间相互转化问题,在实际应用中,JSON对象和数组的结构可能更加复杂,需要根据具体情况进行相应的处理和转换,需要的朋友可以参考下
    2023-07-07
  • 当$.get返回失败后调用fail方法示例详解

    当$.get返回失败后调用fail方法示例详解

    这篇文章主要介绍了当$.get返回失败后,调用fail方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-12-12
  • 小程序模实现糊搜索功能

    小程序模实现糊搜索功能

    这篇文章主要为大家详细介绍了小程序模实现糊搜索功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • js onload处理html页面加载之后的事件

    js onload处理html页面加载之后的事件

    html页面加载之后的事件如何处理,使用js中的window.onload便可轻松做到,需要的朋友可以了解下
    2013-10-10
  • JS开发自己的类库实例分析

    JS开发自己的类库实例分析

    这篇文章主要介绍了JS开发自己的类库,结合实例形式分析了javascript开发类库的原理、组成及实现方法,需要的朋友可以参考下
    2019-08-08
  • JavaScript @umijs/plugin-locale插件使用教程

    JavaScript @umijs/plugin-locale插件使用教程

    这篇文章主要介绍了JavaScript @umijs/plugin-locale插件使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-12-12

最新评论