欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

讓 JavaScript 輕松支持函數(shù)重載 (Part 2 - 實(shí)現(xiàn))

 更新時(shí)間:2009年08月04日 00:20:31   作者:  
在上一篇文章里,我們?cè)O(shè)計(jì)了一套能在JavaScript中描述函數(shù)重載的方法,這套方法依賴(lài)于一個(gè)叫做Overload的靜態(tài)類(lèi),現(xiàn)在我們就來(lái)看看如何實(shí)現(xiàn)這個(gè)靜態(tài)類(lèi)。
識(shí)別文本簽名
我們先來(lái)回顧一下上一篇文章中提到的Overload用例:

復(fù)制代碼 代碼如下:

var extend = Overload
.add("*, ...",
function(target) { })
.add("Boolean, *, ...",
function(deep, target) { });


我們?cè)试S用戶(hù)輸入一個(gè)字符串,表示某一個(gè)重載的簽名。在用戶(hù)調(diào)用函數(shù)時(shí),我們需要拿著用戶(hù)輸入的參數(shù)實(shí)例去跟簽名上的每一個(gè)參數(shù)類(lèi)型作比較,因此我們需要先把這個(gè)字符串轉(zhuǎn)換為類(lèi)型數(shù)組。也就是說(shuō),字符串"Boolean, Number, Array"應(yīng)該轉(zhuǎn)換為數(shù)組[Boolean, Number, Array]。

在進(jìn)行轉(zhuǎn)換之前,我們先要考慮處理兩個(gè)特殊類(lèi)型,就是代表任意類(lèi)型的"*",和代表任意數(shù)量的"..."。我們可以為它們定義兩個(gè)專(zhuān)有的類(lèi)型,以便在Overload內(nèi)對(duì)它們做出特殊的兼容性處理:

復(fù)制代碼 代碼如下:

Overload.Any = function() {};
Overload.More = function() {};


在有了這兩個(gè)類(lèi)型之后,字符串"Boolean, *, ..."就會(huì)被正確轉(zhuǎn)換為數(shù)組[Boolean, Overload.Any, Overload.More]。由于Overload.Any和Overload.More都是函數(shù),自然也都可以看做類(lèi)型。

在這兩個(gè)類(lèi)型得到正確處理后,我們就可以開(kāi)始編寫(xiě)識(shí)別文本簽名的轉(zhuǎn)換函數(shù)了:

復(fù)制代碼 代碼如下:

if (signature.replace(/(^\s+|\s+$)/ig, "") == "") {
signature = [];
} else {
signature = signature.split(",");
for (var i = 0; i < signature.length; i++) {
var typeExpression = signature[i].replace(/(^\s+|\s+$)/ig, "");
var type = null;
if (typeExpression == "*") {
type = Overload.Any;
} else if (typeExpression == "...") {
type = Overload.More;
} else {
type = eval("(" + typeExpression + ")");
}
signature[i] = type;
}
}

我想這段代碼相當(dāng)容易理解,因此就不再解釋了。我第一次寫(xiě)這段代碼時(shí)忘記寫(xiě)上面的第一個(gè)if了,導(dǎo)致空白簽名字符串""無(wú)法被正確識(shí)別為空白簽名數(shù)組[],幸好我的unit test代碼第一時(shí)間發(fā)現(xiàn)了這個(gè)缺陷??磥?lái)編寫(xiě)unit test代碼還是十分重要的。

匹配函數(shù)簽名
在我們得到函數(shù)簽名的類(lèi)型數(shù)組后,我們就可以用它和輸入?yún)?shù)的實(shí)例數(shù)組做匹配了,以此找出正確的重載。在討論具體如何匹配函數(shù)簽名以前,我們先來(lái)看看C#或VB.NET這樣的語(yǔ)言是如何處理函數(shù)重載匹配的。一般語(yǔ)言進(jìn)行函數(shù)重載匹配的流程都是這樣子的:

參數(shù)個(gè)數(shù) - 參數(shù)個(gè)數(shù)不對(duì)的重載會(huì)被排除掉
參數(shù)類(lèi)型 - 參數(shù)類(lèi)型無(wú)法隱式轉(zhuǎn)換為簽名類(lèi)型的會(huì)被排除掉
匹配個(gè)數(shù) - 排除完畢后,剩下匹配的簽名個(gè)數(shù)不同處理方法也不同
0個(gè)匹配 - 沒(méi)有命中的匹配
1個(gè)匹配 - 這個(gè)就是命中的匹配
2個(gè)或以上的匹配 - 如果能在這些匹配中找出一個(gè)最佳匹配,那就命中最佳匹配;否則不命中任何匹配
在這一節(jié)里面,我們先處理流程中的前兩個(gè)步驟,把參數(shù)個(gè)數(shù)或參數(shù)類(lèi)型不一致的簽名去掉:

復(fù)制代碼 代碼如下:

var matchSignature = function(argumentsArray, signature) {
if (argumentsArray.length < signature.length) {
return false;
} else if (argumentsArray.length > signature.length && !signature.more) {
return false;
}
for (var i = 0; i < signature.length; i++) {
if (!(signature[i] == Overload.Any
|| argumentsArray[i] instanceof signature[i]
|| argumentsArray[i].constructor == signature[i])) {
return false;
}
}
return true;
};

為了作長(zhǎng)度對(duì)比,我們需要在這個(gè)函數(shù)外對(duì)表示任何參數(shù)個(gè)數(shù)的"..."作一下特殊處理:

復(fù)制代碼 代碼如下:

if (signature[signature.length - 1] == Overload.More) {
signature.length = signature.length - 1;
signature.more = true;
}


這一段代碼將會(huì)整合到第一節(jié)的轉(zhuǎn)換函數(shù)末端,以便matchSignature函數(shù)能夠輕易判斷出參數(shù)與簽名是否匹配。在最理想的情況下,我們對(duì)輸入?yún)?shù)類(lèi)型匹配到0個(gè)或1個(gè)重載,這樣我們很容易就判斷出命中哪個(gè)重載了。但如果有2個(gè)或以上的重載匹配,那么我們就要從中挑選一個(gè)最優(yōu)的了,這正是下一節(jié)要討論的內(nèi)容。

處理多重匹配
關(guān)于C#是如何從多重匹配中選出較為匹配的重載,可以看C# Language Specification中的有關(guān)章節(jié)。我覺(jué)得通過(guò)三個(gè)簡(jiǎn)單的例子就能說(shuō)明問(wèn)題:

復(fù)制代碼 代碼如下:

long Sum(int x, int y) { return x + y; }
long Sum(long x, long y) { return x + y; }
Sum(0, 1);


由于0和1這兩個(gè)參數(shù)會(huì)被編譯器理解為int類(lèi)型,對(duì)于第1個(gè)重載它們都不用進(jìn)行類(lèi)型轉(zhuǎn)換,都與第2個(gè)重載它們都要進(jìn)行類(lèi)型轉(zhuǎn)換,因此第1個(gè)重載較優(yōu)。

復(fù)制代碼 代碼如下:

long Sum(int x, long y) { return x + y; }
long Sum(long x, int y) { return x + y; }
Sum(0, 1);


在第1個(gè)參數(shù)上,第1個(gè)重載較優(yōu);在第2個(gè)參數(shù)上,第2個(gè)重載較優(yōu)。在這種情況下,任何一個(gè)重載都不優(yōu)于另一個(gè),找不到較優(yōu)重載編譯器就報(bào)錯(cuò)。

復(fù)制代碼 代碼如下:

long Sum(int x, int y) { return x + y; }
long Sum(int x, long y) { return x + y; }
long Sum(long x, int y) { return x + y; }
Sum(0, 1);


在第1個(gè)參數(shù)上,第1個(gè)重載優(yōu)于第3個(gè)重載,于第2個(gè)重載無(wú)異;在第2個(gè)參數(shù)上,第1個(gè)重載優(yōu)于第2個(gè)重載,于第3個(gè)重載無(wú)異。盡管第2個(gè)重載于第3個(gè)重載分不出個(gè)優(yōu)劣來(lái),但我們可以確定第1個(gè)重載比它們都要好,因此編譯器選擇了第1個(gè)重載。

假設(shè)我們有一個(gè)overloadComparator的比較函數(shù),可以比較任意兩個(gè)簽名之間的優(yōu)劣,我們需要對(duì)簽名僅僅兩兩比較,以找出最優(yōu)重載嗎?事實(shí)上是不需要的,我們可以利用Array的sort方法,讓它調(diào)用overloadComparator進(jìn)行排序,排序后再驗(yàn)證前兩名的關(guān)系就可以了——如果并列,則不命中任何一個(gè);如果有先后之分,則命中第一個(gè)。

具體的overloadComparator代碼就不在這里給出了,它依賴(lài)于另一個(gè)名為inheritanceComparator的比較函數(shù)來(lái)對(duì)比兩個(gè)簽名的參數(shù)類(lèi)型哪一個(gè)更貼實(shí)際傳入的參數(shù)類(lèi)型,里面用到了一種比較巧妙的方法來(lái)判斷兩個(gè)類(lèi)型是否為繼承關(guān)系,以及是誰(shuí)繼承自誰(shuí)。

小結(jié)
現(xiàn)在我們有了一個(gè)JavaScript的函數(shù)重載庫(kù),完整代碼請(qǐng)看這里:函數(shù)重載庫(kù)Overload。希望這個(gè)庫(kù)能有效幫助大家提升JavaScript代碼的可讀性,降低大型Ajax項(xiàng)目的維護(hù)成本。

相關(guān)文章

最新評(píng)論