JavaScript 通過模式匹配實(shí)現(xiàn)重載
更新時(shí)間:2010年08月12日 10:19:12 作者:
昨天rank同學(xué)向我提出一個(gè)問題,在實(shí)際應(yīng)用中有些接口需要提供類似于函數(shù)重載的功能,以方便開發(fā)者組織代碼邏輯,簡(jiǎn)化使用者調(diào)用。
正好infinte同學(xué)提出“更優(yōu)雅的兼容”其實(shí)也和這個(gè)問題有一定的關(guān)聯(lián)(我們后面會(huì)看到)
在youa的腳本庫(kù)中Function的Helper中,添加支持重載的模式匹配
/**
* 函數(shù)參數(shù)重載方法 overload,對(duì)函數(shù)參數(shù)進(jìn)行模式匹配。默認(rèn)的dispatcher支持*和...以及?,"*"表示一個(gè)任意類型的參數(shù),"..."表示多個(gè)任意類型的參數(shù),"?"一般用在",?..."表示0個(gè)或任意多個(gè)參數(shù)
* @method overload
* @static
* @optional {dispatcher} 用來匹配參數(shù)負(fù)責(zé)派發(fā)的函數(shù)
* @param {func_maps} 根據(jù)匹配接受調(diào)用的函數(shù)列表
* @return {function} 已重載化的函數(shù)
*/
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 包括兩個(gè)參數(shù),一個(gè)是負(fù)責(zé)處理匹配條件的dispatcher函數(shù)(可缺?。?,另一個(gè)是一組函數(shù)映射表,默認(rèn)dispatcher函數(shù)是根據(jù)實(shí)際調(diào)用的參數(shù)類型生成一個(gè)字符串,例如調(diào)用的三個(gè)參數(shù)依次為10、”a”、[1,2]將生成”number,string,array”,具體實(shí)現(xiàn)模式匹配的時(shí)候,將根據(jù)函數(shù)映射表的每一個(gè)”key”生成一個(gè)正則表達(dá)式,用這個(gè)正則表達(dá)式匹配dispatcher函數(shù)的返回值,如果匹配,則調(diào)用這個(gè)key對(duì)應(yīng)的處理函數(shù),否則依次匹配下一個(gè)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 可以優(yōu)化為:
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,這種形式在一些人看來或許已經(jīng)比原來看起來好一些了,但是其實(shí)還可以更進(jìn)一步的——
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;
}
}),
還有“討厭”的第三個(gè)參數(shù),干脆也一并處理了——
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;
}
}),
例如說瀏覽器嗅探和特性探測(cè)之類種種,同理也能采用這個(gè)模式(當(dāng)然這種形式有利有弊,使用者自己權(quán)衡吧)——
foo = FunctionH.overload(function() {
return MSIE ? "IE": "NotIE";
},{
"IE": function() {...}
"NotIE": function() {...}
});
在youa的腳本庫(kù)中Function的Helper中,添加支持重載的模式匹配
復(fù)制代碼 代碼如下:
/**
* 函數(shù)參數(shù)重載方法 overload,對(duì)函數(shù)參數(shù)進(jìn)行模式匹配。默認(rèn)的dispatcher支持*和...以及?,"*"表示一個(gè)任意類型的參數(shù),"..."表示多個(gè)任意類型的參數(shù),"?"一般用在",?..."表示0個(gè)或任意多個(gè)參數(shù)
* @method overload
* @static
* @optional {dispatcher} 用來匹配參數(shù)負(fù)責(zé)派發(fā)的函數(shù)
* @param {func_maps} 根據(jù)匹配接受調(diào)用的函數(shù)列表
* @return {function} 已重載化的函數(shù)
*/
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 包括兩個(gè)參數(shù),一個(gè)是負(fù)責(zé)處理匹配條件的dispatcher函數(shù)(可缺?。?,另一個(gè)是一組函數(shù)映射表,默認(rèn)dispatcher函數(shù)是根據(jù)實(shí)際調(diào)用的參數(shù)類型生成一個(gè)字符串,例如調(diào)用的三個(gè)參數(shù)依次為10、”a”、[1,2]將生成”number,string,array”,具體實(shí)現(xiàn)模式匹配的時(shí)候,將根據(jù)函數(shù)映射表的每一個(gè)”key”生成一個(gè)正則表達(dá)式,用這個(gè)正則表達(dá)式匹配dispatcher函數(shù)的返回值,如果匹配,則調(diào)用這個(gè)key對(duì)應(yīng)的處理函數(shù),否則依次匹配下一個(gè)key,例如:
復(fù)制代碼 代碼如下:
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 可以優(yōu)化為:
復(fù)制代碼 代碼如下:
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,這種形式在一些人看來或許已經(jīng)比原來看起來好一些了,但是其實(shí)還可以更進(jìn)一步的——
復(fù)制代碼 代碼如下:
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;
}
}),
還有“討厭”的第三個(gè)參數(shù),干脆也一并處理了——
復(fù)制代碼 代碼如下:
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;
}
}),
例如說瀏覽器嗅探和特性探測(cè)之類種種,同理也能采用這個(gè)模式(當(dāng)然這種形式有利有弊,使用者自己權(quán)衡吧)——
復(fù)制代碼 代碼如下:
foo = FunctionH.overload(function() {
return MSIE ? "IE": "NotIE";
},{
"IE": function() {...}
"NotIE": function() {...}
});
相關(guān)文章
基于JavaScript實(shí)現(xiàn)生成名片、鏈接等二維碼
本文使用javascript技術(shù)實(shí)現(xiàn)生成名片、鏈接等二維碼的代碼,代碼簡(jiǎn)單易懂并附有注釋,需要的朋友可以參考下本文2015-09-09關(guān)于javascript中json 對(duì)象數(shù)組之間相互轉(zhuǎn)化問題
這篇文章主要介紹了關(guān)于javascript中json 對(duì)象數(shù)組之間相互轉(zhuǎn)化問題,在實(shí)際應(yīng)用中,JSON對(duì)象和數(shù)組的結(jié)構(gòu)可能更加復(fù)雜,需要根據(jù)具體情況進(jìn)行相應(yīng)的處理和轉(zhuǎn)換,需要的朋友可以參考下2023-07-07當(dāng)$.get返回失敗后調(diào)用fail方法示例詳解
這篇文章主要介紹了當(dāng)$.get返回失敗后,調(diào)用fail方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-12-12JavaScript @umijs/plugin-locale插件使用教程
這篇文章主要介紹了JavaScript @umijs/plugin-locale插件使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-12-12