正好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() {...}
});