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 相关文章推荐
简单常用的幻灯片播放实现代码
Sep 25 Javascript
XMLHttpRequest处理xml格式的返回数据(示例代码)
Nov 21 Javascript
JavaScript获得页面base标签中url的方法
Apr 03 Javascript
谈谈PHP中相对路径的问题与绝对路径的使用
Aug 16 Javascript
微信小程序 location API实例详解
Oct 02 Javascript
js实现随机抽选效果、随机抽选红色球效果
Jan 13 Javascript
vue2的todolist入门小项目的详细解析
May 11 Javascript
Angularjs修改密码的实例代码
May 26 Javascript
bmob js-sdk 在vue中的使用教程
Jan 21 Javascript
对node.js中render和send的用法详解
May 14 Javascript
JS 实现发送短信验证码的“59秒后重新发送验证短信”功能
Aug 23 Javascript
JavaScript arguments.callee作用及替换方案详解
Sep 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 获取本机外网/公网IP的代码
2010/05/09 PHP
PHP中全局变量global和$GLOBALS[]的区别分析
2012/08/06 PHP
PHP解析目录路径的3个函数总结
2014/11/18 PHP
详解WordPress中过滤链接与过滤SQL语句的方法
2015/12/18 PHP
Yii实现单用户博客系统文章详情页插入评论表单的方法
2015/12/28 PHP
PHP使用curl函数发送Post请求的注意事项
2016/11/26 PHP
Laravel 5.5基于内置的Auth模块实现前后台登陆详解
2017/12/21 PHP
用js判断用户浏览器是否是XP SP2的IE6
2007/03/08 Javascript
javascript options属性集合操作代码
2009/12/28 Javascript
重构Javascript代码示例(重构前后对比)
2013/01/23 Javascript
探讨js字符串数组拼接的性能问题
2014/10/11 Javascript
一个检测表单数据的JavaScript实例
2014/10/31 Javascript
JS实现按比例缩放图片的方法(附C#版代码)
2015/12/08 Javascript
七个不允许错过的jQuery小技巧
2015/12/21 Javascript
Bootstrap Modal遮罩弹出层(完整版)
2016/11/21 Javascript
利用JS测试目标网站的打开响应速度
2017/12/01 Javascript
微信小程序身份证验证方法实现详解
2019/06/28 Javascript
浅谈layer的Icon样式以及一些常用的layer窗口使用方法
2019/09/11 Javascript
vue + elementUI实现省市县三级联动的方法示例
2019/10/29 Javascript
javascript数组元素删除方法delete和splice解析
2019/12/09 Javascript
python实现的生成随机迷宫算法核心代码分享(含游戏完整代码)
2014/07/11 Python
Python图算法实例分析
2016/08/13 Python
怎样使用Python脚本日志功能
2016/08/14 Python
Python实现小数转化为百分数的格式化输出方法示例
2017/09/20 Python
python 匹配url中是否存在IP地址的方法
2018/06/04 Python
浅谈django三种缓存模式的使用及注意点
2018/09/30 Python
解决Python pandas plot输出图形中显示中文乱码问题
2018/12/12 Python
python 如何去除字符串头尾的多余符号
2019/11/19 Python
Python实现图片批量加入水印代码实例
2019/11/30 Python
python使用html2text库实现从HTML转markdown的方法详解
2020/02/21 Python
Python验证码截取识别代码实例
2020/05/16 Python
CSS3 icon font完全指南(CSS3 font 会取代icon图标)
2013/01/06 HTML / CSS
台湾生鲜宅配:大口市集
2017/10/14 全球购物
拉斯维加斯城市观光通行证:Las Vegas Pass
2019/05/21 全球购物
网络编辑岗位职责范本
2014/02/10 职场文书
通用自荐信范文
2014/03/14 职场文书