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