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 相关文章推荐
javascript的trim,ltrim,rtrim自定义函数
Sep 21 Javascript
jquery checkbox,radio是否选中的判断代码
Mar 20 Javascript
javascript生成json数据简单示例分享
Feb 14 Javascript
用javascript对一个json数组深度赋值示例
Jul 27 Javascript
jQuery实现按键盘方向键翻页特效
Mar 18 Javascript
jQuery的load()方法及其回调函数用法实例
Mar 25 Javascript
javascript实现通过表格绘制颜色填充矩形的方法
Apr 21 Javascript
浅谈JS原生Ajax,GET和POST
Jun 08 Javascript
Node.js制作简单聊天室
Jan 12 Javascript
微信小程序使用Socket的实例
Sep 19 Javascript
Vue CLI3创建项目部署到Tomcat 使用ngrok映射到外网
May 16 Javascript
vue实现浏览器全屏展示功能
Nov 27 Javascript
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
基于文本的访客签到簿
2006/10/09 PHP
从php核心代码分析require和include的区别
2011/01/02 PHP
PHP不用递归遍历目录下所有文件的代码
2014/07/04 PHP
php获取百度收录、百度热词及百度快照的方法
2015/04/02 PHP
CodeIgniter配置之SESSION用法实例分析
2016/01/19 PHP
PHP asXML()函数讲解
2019/02/03 PHP
ASP中进行HTML数据及JS数据编码函数
2009/11/11 Javascript
js登录弹出层特效
2014/03/07 Javascript
window.location.href的用法(动态输出跳转)
2014/08/09 Javascript
node.js中的path.normalize方法使用说明
2014/12/08 Javascript
使用jquery菜单插件HoverTree仿京东无限级菜单
2014/12/18 Javascript
js实现图片和链接文字同步切换特效的方法
2015/02/20 Javascript
JS实现点击按钮后框架内载入不同网页的方法
2015/05/05 Javascript
JS实用的动画弹出层效果实例
2015/05/05 Javascript
JavaScript识别网页关键字并进行描红的方法
2015/11/09 Javascript
JS提示:Uncaught SyntaxError: Unexpected token ILLEGAL错误的解决方法
2016/08/19 Javascript
jQuery对table表格进行增删改查
2020/12/22 Javascript
JS实现的对象去重功能示例
2019/06/04 Javascript
python绘图方法实例入门
2015/05/19 Python
浅谈python 线程池threadpool之实现
2017/11/17 Python
深入浅析python 中的匿名函数
2018/05/21 Python
python 自动去除空行的实例
2018/07/24 Python
python版飞机大战代码分享
2018/11/20 Python
python实现对任意大小图片均匀切割的示例
2018/12/05 Python
只需7行Python代码玩转微信自动聊天
2019/01/27 Python
django mysql数据库及图片上传接口详解
2019/07/18 Python
pycharm配置python 设置pip安装源为豆瓣源
2021/02/05 Python
美国女士泳装店:Swimsuits For All
2017/03/02 全球购物
英国音乐设备和乐器商店:Gear4music
2017/10/16 全球购物
这76道Java面试题及答案,祝你能成功通过面试
2016/04/16 面试题
采购部经理岗位职责
2014/02/10 职场文书
擅自离岗检讨书
2014/02/11 职场文书
学校庆元旦歌咏比赛主持词
2014/03/18 职场文书
2015年维修工作总结
2015/04/25 职场文书
2016年小学教师政治学习心得体会
2016/01/23 职场文书
网络安全倡议书(3篇)
2019/09/18 职场文书