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之querySelector和querySelectorAll使用说明
Oct 09 Javascript
JavaScript高级程序设计 阅读笔记(四) ECMAScript中的类型转换
Feb 27 Javascript
js open() 与showModalDialog()方法使用介绍
Sep 10 Javascript
fixedBox固定div漂浮代码支持ie6以上大部分主流浏览器
Jun 26 Javascript
基于jquery实现一个滚动的分步注册向导-附源码
Aug 26 Javascript
JavaScript中this的四个绑定规则总结
Sep 26 Javascript
jQuery Validation Engine验证控件调用外部函数验证的方法
Jan 18 Javascript
vue组件Prop传递数据的实现示例
Aug 17 Javascript
使用Node搭建reactSSR服务端渲染架构
Aug 30 Javascript
浅谈Vue render函数在ElementUi中的应用
Sep 06 Javascript
利用Vconsole和Fillder进行移动端抓包调试方法
Mar 05 Javascript
基于iview-admin实现动态路由的示例代码
Oct 02 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创建动态图像
2006/10/09 PHP
php下将图片以二进制存入mysql数据库中并显示的实现代码
2010/05/27 PHP
PHP内置的Math函数效率测试
2014/12/01 PHP
php网页病毒清除类
2014/12/08 PHP
PHP环形链表实现方法示例
2017/09/15 PHP
读jQuery之六 缓存数据功能介绍
2011/06/21 Javascript
nullJavascript中创建对象的五种方法实例
2013/05/07 Javascript
JS动态改变浏览器标题的方法
2016/04/06 Javascript
最全面的JS倒计时代码
2016/09/17 Javascript
前端设计师们最常用的JS代码汇总
2016/09/25 Javascript
基于vue实现swipe轮播组件实例代码
2017/05/24 Javascript
js如何编写简单的ajax方法库
2017/08/02 Javascript
vue仿淘宝订单状态的tab切换效果
2020/06/23 Javascript
解决vue中修改export default中脚本报一大堆错的问题
2018/08/27 Javascript
JavaScript使用类似break机制中断forEach循环的方法
2018/11/13 Javascript
vue-test-utils初使用详解
2019/05/23 Javascript
extjs4图表绘制之折线图实现方法分析
2020/03/06 Javascript
详谈Vue.js框架下main.js,App.vue,page/index.vue之间的区别
2020/08/12 Javascript
Python中的localtime()方法使用详解
2015/05/22 Python
python的变量与赋值详细分析
2017/11/08 Python
教你用 Python 实现微信跳一跳(Mac+iOS版)
2018/01/04 Python
Python实现快速傅里叶变换的方法(FFT)
2018/07/21 Python
python实现多人聊天室
2020/03/31 Python
对pyqt5之menu和action的使用详解
2019/06/20 Python
pandas对dataFrame中某一个列的数据进行处理的方法
2019/07/08 Python
tensorflow如何继续训练之前保存的模型实例
2020/01/21 Python
python 绘制正态曲线的示例
2020/09/24 Python
Flask中jinja2的继承实现方法及实例
2021/03/03 Python
Sandro法国官网:法国成衣品牌
2019/08/28 全球购物
全球最大的瓷器、水晶和银器零售商:Replacements
2020/06/15 全球购物
森林防火工作方案
2014/02/14 职场文书
中班中秋节活动反思
2014/02/18 职场文书
正风肃纪查摆剖析材料
2014/10/10 职场文书
小学运动会前导词
2015/07/20 职场文书
企业管理不到位检讨书
2019/06/27 职场文书
React列表栏及购物车组件使用详解
2021/06/28 Javascript