讓 JavaScript 輕松支持函數重載 (Part 2 - 實現)
2024-05-06 14:14:32
供稿:網友
識別文本簽名
我們先來回顧一下上一篇文章中提到的Overload用例:
代碼如下:
var extend = Overload
.add("*, ...",
function(target) { })
.add("Boolean, *, ...",
function(deep, target) { });
我們允許用戶輸入一個字符串,表示某一個重載的簽名。在用戶調用函數時,我們需要拿著用戶輸入的參數實例去跟簽名上的每一個參數類型作比較,因此我們需要先把這個字符串轉換為類型數組。也就是說,字符串"Boolean, Number, Array"應該轉換為數組[Boolean, Number, Array]。
在進行轉換之前,我們先要考慮處理兩個特殊類型,就是代表任意類型的"*",和代表任意數量的"..."。我們可以為它們定義兩個專有的類型,以便在Overload內對它們做出特殊的兼容性處理:
代碼如下:
Overload.Any = function() {};
Overload.More = function() {};
在有了這兩個類型之后,字符串"Boolean, *, ..."就會被正確轉換為數組[Boolean, Overload.Any, Overload.More]。由于Overload.Any和Overload.More都是函數,自然也都可以看做類型。
在這兩個類型得到正確處理后,我們就可以開始編寫識別文本簽名的轉換函數了:
代碼如下:
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;
}
}
我想這段代碼相當容易理解,因此就不再解釋了。我第一次寫這段代碼時忘記寫上面的第一個if了,導致空白簽名字符串""無法被正確識別為空白簽名數組[],幸好我的unit test代碼第一時間發現了這個缺陷。看來編寫unit test代碼還是十分重要的。
匹配函數簽名
在我們得到函數簽名的類型數組后,我們就可以用它和輸入參數的實例數組做匹配了,以此找出正確的重載。在討論具體如何匹配函數簽名以前,我們先來看看C#或VB.NET這樣的語言是如何處理函數重載匹配的。一般語言進行函數重載匹配的流程都是這樣子的:
參數個數 - 參數個數不對的重載會被排除掉
參數類型 - 參數類型無法隱式轉換為簽名類型的會被排除掉
匹配個數 - 排除完畢后,剩下匹配的簽名個數不同處理方法也不同
0個匹配 - 沒有命中的匹配
1個匹配 - 這個就是命中的匹配
2個或以上的匹配 - 如果能在這些匹配中找出一個最佳匹配,那就命中最佳匹配;否則不命中任何匹配
在這一節里面,我們先處理流程中的前兩個步驟,把參數個數或參數類型不一致的簽名去掉: