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 相关文章推荐
JS 实现导航栏悬停效果
Sep 23 Javascript
js触发select onchange事件的小技巧
Aug 05 Javascript
整理AngularJS框架使用过程当中的一些性能优化要点
Mar 05 Javascript
JavaScript每天必学之数组和对象部分
Sep 17 Javascript
JS访问DOM节点方法详解
Nov 29 Javascript
AngularJS模仿Form表单提交的实现代码
Dec 08 Javascript
webpack构建vue项目的详细教程(配置篇)
Jul 17 Javascript
js与jQuery实现获取table中的数据并拼成json字符串操作示例
Jul 12 jQuery
浅谈ElementUI中switch回调函数change的参数问题
Aug 24 Javascript
vue template中slot-scope/scope的使用方法
Sep 06 Javascript
微信小程序实现两个页面传值的方法分析
Dec 11 Javascript
jQuery使用ajax传递json对象到服务端及contentType的用法示例
Mar 12 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
解析关于wamp启动是80端口被占用的问题
2013/06/21 PHP
高性能PHP框架Symfony2经典入门教程
2014/07/08 PHP
PHP判断来访是搜索引擎蜘蛛还是普通用户的代码小结
2015/09/14 PHP
js控制网页前进和后退的方法
2015/06/08 Javascript
javaScript中push函数用法实例分析
2015/06/08 Javascript
用NODE.JS中的流编写工具是要注意的事项
2016/03/01 Javascript
jQuery实现对无序列表的排序功能(附demo源码下载)
2016/06/25 Javascript
jquery easyui DataGrid简单示例
2017/01/23 Javascript
angular6 利用 ngContentOutlet 实现组件位置交换(重排)
2018/11/02 Javascript
JS数组求和的常用方法总结【5种方法】
2019/01/14 Javascript
js图数据结构处理 迪杰斯特拉算法代码实例
2019/09/11 Javascript
js实现经典贪吃蛇小游戏
2020/03/19 Javascript
vue 使用原生组件上传图片的实例
2020/09/08 Javascript
Python中的XML库4Suite Server的介绍
2015/04/14 Python
关于pip的安装,更新,卸载模块以及使用方法(详解)
2017/05/19 Python
Flask框架响应、调度方法和蓝图操作实例分析
2018/07/24 Python
python调用c++ ctype list传数组或者返回数组的方法
2019/02/13 Python
Python实现微信自动好友验证,自动回复,发送群聊链接方法
2019/02/21 Python
深入浅析python 协程与go协程的区别
2019/05/09 Python
解决pycharm 工具栏Tool中找不到Run manager.py Task的问题
2019/07/01 Python
python 返回一个列表中第二大的数方法
2019/07/09 Python
在python中实现同行输入/接收多个数据的示例
2019/07/20 Python
Python使用百度翻译开发平台实现英文翻译为中文功能示例
2019/08/08 Python
在keras中实现查看其训练loss值
2020/06/16 Python
linux centos 7.x 安装 python3.x 替换 python2.x的过程解析
2020/12/14 Python
button在IE6/7下的黑边去除方案
2012/12/24 HTML / CSS
CSS图片翻转动画技术详解(IE也实现了)
2014/04/03 HTML / CSS
移动端适配 使px自动转换rem
2019/08/26 HTML / CSS
html5表单及新增的改良元素详解
2016/06/07 HTML / CSS
采购人员的个人自我评价
2014/01/16 职场文书
幼儿园新学期寄语
2014/01/18 职场文书
银行纠风工作实施方案
2014/06/08 职场文书
个人委托书如何写
2014/09/25 职场文书
施工安全协议书范本
2014/09/26 职场文书
新生开学寄语大全
2015/05/28 职场文书
elasticSearch-api的具体操作步骤讲解
2021/06/28 Java/Android