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 相关文章推荐
jquery 页面全选框实践代码
Apr 02 Javascript
jQuery选择没有colspan属性的td的代码
Jul 06 Javascript
javascript 进阶篇2 CSS XML学习
Mar 14 Javascript
js快速排序的实现代码
Dec 08 Javascript
jquery 通过name快速取值示例
Jan 24 Javascript
百度判断手机终端并自动跳转js代码及使用实例
Jun 11 Javascript
jQuery简单几行代码实现tab切换
Mar 10 Javascript
关于页面刷新vuex数据消失问题解决方案
Jul 03 Javascript
Angular2 父子组件通信方式的示例
Jan 29 Javascript
Vue中使用clipboard实现复制功能
Sep 05 Javascript
axios 实现post请求时把对象obj数据转为formdata
Oct 31 Javascript
Vue.directive 实现元素scroll逻辑复用
Nov 29 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
使用adodb lite解决问题
2006/12/31 PHP
php5 non-thread-safe和thread-safe这两个版本的区别分析
2010/03/13 PHP
php自动给文章加关键词链接的函数代码
2012/11/29 PHP
PHP中time(),date(),mktime()区别介绍
2013/09/28 PHP
PHP大转盘中奖概率算法实例
2014/10/21 PHP
thinkPHP5.0框架引入Traits功能实例分析
2017/03/18 PHP
PHP使用gearman进行异步的邮件或短信发送操作详解
2020/02/27 PHP
老鱼 浅谈javascript面向对象编程
2010/03/04 Javascript
判断目标是否是window,document,和拥有tagName的Element的代码
2010/05/31 Javascript
js实现目录定位正文示例
2013/11/14 Javascript
JS冒泡事件的快速解决方法
2013/12/16 Javascript
以JSON形式将JS中Array对象数组传至后台的方法
2014/01/06 Javascript
jquery.form.js框架实现文件上传功能案例解析(springmvc)
2016/05/26 Javascript
jquery pagination分页插件使用详解(后台struts2)
2017/01/22 Javascript
angularJS 发起$http.post和$http.get请求的实现方法
2017/05/18 Javascript
简单谈谈关于Angular Cli打包的事
2017/09/05 Javascript
Vue精简版风格概述
2018/01/30 Javascript
JS中Map和ForEach的区别
2018/02/05 Javascript
jQuery实现的点击按钮改变样式功能示例
2018/07/21 jQuery
深入浅出 Vue 系列 -- 数据劫持实现原理
2019/04/23 Javascript
基于JS实现一个随机生成验证码功能
2019/05/29 Javascript
过滤器vue.filters的使用方法实现
2019/09/18 Javascript
记录一次websocket封装的过程
2020/11/23 Javascript
[54:27]TNC vs Serenity 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
在Python中使用SQLite的简单教程
2015/04/29 Python
Python制作刷网页流量工具
2017/04/23 Python
如何在scrapy中集成selenium爬取网页的方法
2020/11/18 Python
python将下载到本地m3u8视频合成MP4的代码详解
2020/11/24 Python
python中Mako库实例用法
2020/12/31 Python
《有趣的发现》教学反思
2014/04/15 职场文书
采购内勤岗位职责
2015/04/13 职场文书
2015年高校教师个人工作总结
2015/05/25 职场文书
七一晚会主持词
2015/06/29 职场文书
2015年度学校应急管理工作总结
2015/10/22 职场文书
写作技巧:如何撰写一份优秀的营销策划书
2019/08/13 职场文书
基于Java的MathML转图片的方法(示例代码)
2021/06/23 Java/Android