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 相关文章推荐
IE 缓存策略的BUG的解决方法
Jul 21 Javascript
javascript 原型模式实现OOP的再研究
Apr 09 Javascript
Javascript中的this绑定介绍
Sep 22 Javascript
同域jQuery(跨)iframe操作DOM(示例代码)
Dec 13 Javascript
node.js中的fs.utimesSync方法使用说明
Dec 15 Javascript
Jquery操作Ajax方法小结
Nov 29 Javascript
获取JS中网页各种高宽与位置的方法总结
Jul 27 Javascript
js自调用匿名函数的三种写法(推荐)
Aug 19 Javascript
jQuery Easy UI中根据第一个下拉框选中的值设置第二个下拉框是否可以编辑
Nov 29 Javascript
Vue开发之封装分页组件与使用示例
Apr 25 Javascript
Vue数据双向绑定底层实现原理
Nov 22 Javascript
微信小程序实现modal弹出框遮罩层组件(可带文本框)
Dec 20 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
PHP has encountered an Access Violation
2007/01/15 PHP
PHP-MySQL教程归纳总结
2008/06/07 PHP
使用PHP破解防盗链图片的一个简单方法
2014/06/07 PHP
prototype 中文参数乱码解决方案
2009/11/09 Javascript
ExtJS 设置级联菜单的默认值
2010/06/13 Javascript
深入理解javaScript中的事件驱动
2013/05/21 Javascript
基于pthread_create,readlink,getpid等函数的学习与总结
2013/07/17 Javascript
JQuery删除DOM节点的方法
2015/06/11 Javascript
谈谈AngularJs中的隐藏和显示
2015/12/09 Javascript
jquery实现百叶窗效果
2017/01/12 Javascript
Node.js调试技术总结分享
2017/03/12 Javascript
JavaScript数组和对象的复制
2017/03/21 Javascript
浅谈AngularJS中使用$resource(已更新)
2017/09/14 Javascript
小程序如何写动态标签的实现方法
2020/02/05 Javascript
javascript实现滚动条效果
2020/03/24 Javascript
基于JS实现视频上传显示进度条
2020/05/12 Javascript
对pandas进行数据预处理的实例讲解
2018/04/20 Python
python中plot实现即时数据动态显示方法
2018/06/22 Python
Django中的Model操作表的实现
2018/07/24 Python
PyQt5 QTableView设置某一列不可编辑的方法
2019/06/25 Python
使用Python的turtle模块画国旗
2019/09/24 Python
Numpy 多维数据数组的实现
2020/06/18 Python
python中_del_还原数据的方法
2020/12/09 Python
python中append函数用法讲解
2020/12/11 Python
德国箱包网上商店:koffer24.de
2016/07/27 全球购物
医疗保健专业人士购物网站:Scrubs & Beyond
2017/02/08 全球购物
在线购买廉价折扣书籍和小说:BookOutlet.com
2018/02/19 全球购物
中国专业的音频分享平台:喜马拉雅
2019/05/24 全球购物
Onzie官网:美国时尚瑜伽品牌
2019/08/21 全球购物
Monki官网:斯堪的纳维亚的独立时尚品牌
2020/11/09 全球购物
三好学生个人先进事迹材料
2014/05/17 职场文书
个人欠条范本
2015/07/03 职场文书
毕业生求职自荐信(2016最新版)
2016/01/28 职场文书
《钓鱼的启示》教学反思
2016/02/18 职场文书
spring cloud 配置中心客户端启动遇到的问题
2021/09/25 Java/Android
python小型的音频操作库mp3Play
2022/04/24 Python