JavaScript 通过模式匹配实现重载


Posted in Javascript onAugust 12, 2010

正好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 相关文章推荐
文字溢出实现溢出的部分再放入一个新生成的div中具体代码
May 17 Javascript
javascript获取URL参数与参数值的示例代码
Dec 20 Javascript
js实现超简单的展开、折叠目录代码
Aug 28 Javascript
js中substr,substring,indexOf,lastIndexOf,split,replace的用法详解
Nov 09 Javascript
jQuery动画显示和隐藏效果实例演示(附demo源码下载)
Dec 31 Javascript
jQuery模拟物体自由落体运动(附演示与demo源码下载)
Jan 21 Javascript
Javascript中Date类型和Math类型详解
Feb 27 Javascript
javascript数组去重小结
Mar 07 Javascript
angular基于路由控制ui-router实现系统权限控制
Sep 27 Javascript
JS中事件冒泡和事件捕获介绍
Dec 13 Javascript
node实现mock-plugin中间件的方法
Dec 25 Javascript
jquery绑定事件 bind和on的用法与区别分析
May 22 jQuery
js更优雅的兼容
Aug 12 #Javascript
页面只有一个text的时候,回车自动submit的解决方法
Aug 12 #Javascript
javascript闭包的理解和实例
Aug 12 #Javascript
javascript 词法作用域和闭包分析说明
Aug 12 #Javascript
判断客户端浏览器是否安装了Flash插件的多种方法
Aug 11 #Javascript
基于JQuery的数字改变的动画效果--可用来做计数器
Aug 11 #Javascript
JQuery最佳实践之精妙的自定义事件
Aug 11 #Javascript
You might like
《魔兽争霸3:重制版》更新 多项视觉效果调整
2020/05/04 魔兽争霸
实时抓取YAHOO股票报价的代码
2006/10/09 PHP
Laravel 5框架学习之表单
2015/04/08 PHP
PHP嵌套输出缓冲代码实例
2015/05/12 PHP
详解PHP序列化反序列化的方法
2015/10/27 PHP
关于PHP5.6+版本“No input file specified”问题的解决
2019/12/11 PHP
Javascript调用XML制作连动下拉列表框
2006/06/25 Javascript
javascript实现上传图片前的预览(TX的面试题)
2007/08/20 Javascript
使用jQuery和PHP实现类似360功能开关效果
2014/02/12 Javascript
jquery实现简单手风琴菜单效果实例
2015/06/13 Javascript
jquery实现点击其他区域时隐藏下拉div和遮罩层的方法
2015/12/23 Javascript
jQuery插件FusionCharts实现的Marimekko图效果示例【附demo源码】
2017/03/24 jQuery
vue axios请求拦截实例代码
2018/03/29 Javascript
JS实现常见的查找、排序、去重算法示例
2018/05/21 Javascript
js隐式转换的知识实例讲解
2018/09/28 Javascript
微信小程序实现炫酷的弹出式菜单特效
2019/01/28 Javascript
JS实现继承的几种常用方式示例
2019/06/22 Javascript
在vue中配置不同的代理同时访问不同的后台操作
2020/09/11 Javascript
[46:44]VG vs TNC Supermajor小组赛B组败者组决赛 BO3 第一场 6.2
2018/06/03 DOTA
Python装饰器decorator用法实例
2014/11/10 Python
详解Python中的join()函数的用法
2015/04/07 Python
pandas获取groupby分组里最大值所在的行方法
2018/04/20 Python
Python3 中把txt数据文件读入到矩阵中的方法
2018/04/27 Python
django 使用 PIL 压缩图片的例子
2019/08/16 Python
django配置app中的静态文件步骤
2020/03/27 Python
CSS3实现大小不一的粒子旋转加载动画
2016/04/21 HTML / CSS
英国男士时尚网站:Dandy Fellow
2018/02/09 全球购物
Helly Hansen工作服美国官方网上商店:为最恶劣的环境
2019/09/04 全球购物
给校长的建议书300字
2014/05/16 职场文书
2015年幼儿教师个人工作总结
2015/05/20 职场文书
2015年三年级班主任工作总结
2015/05/21 职场文书
大学生读书笔记大全
2015/07/01 职场文书
2016年党支部公开承诺书
2016/03/25 职场文书
如何判断pytorch是否支持GPU加速
2021/06/01 Python
十大公认最好看的动漫:《咒术回战》在榜,《钢之炼金术师》第一
2022/03/18 日漫
instantclient客户端 连接oracle数据库
2022/04/26 Oracle