函數重載和類型檢查
其它物件導向的語言(比如Java)的一種共有的特性是“重載”函數的能力:傳給它們不同數目或類型的參數,函數將執行不同操作。雖然這種能力在JavaScript中不是直接可用的,一些工具的提供使得這種探求完全成為可能。
在JavaScript的每一個函數裡存在一個上下文相關的名為arguments的變數,它的行為類似於一個偽數組,包含了傳給函數的所有參數。參數不是一真正的數組(意味著你不能修改它,或者調用push()方法增加新的項),但是你可以以數組的形式訪問它,而且它也的確有一個length屬性。程式2-5中有兩個樣本。
程式2-5. JavaScript中函數重載的兩個樣本
//一個簡單的用來發送訊息的函數
function sendMessage( msg, obj ) {
//如果同時提供了一個訊息和一個對象
if ( arguments.length == 2 )
//就將訊息發給該對象
obj.handleMsg( msg );
//否則,剛假定只有訊息被提供
else
//於是顯示該訊息
alert( msg );
}
//調用函數,帶一個參數 – 用警告框顯示訊息
sendMessage( "Hello, World!" );
//或者,我們也可以傳入我們自己的對象用
//一種不同方式來顯示資訊
sendMessage( "How are you?", {
handleMsg: function( msg ) {
alert( "This is a custom message: " + msg );
}
});
//一個使用任意數目參數建立一個數組的函數
function makeArray() {
//臨時數組
var arr = [];
//遍曆提交的每一個參數
for ( var i = 0; i < arguments.length; i++ ) {
arr.push( arguments[i] );
}
//返回結果數組
return arr;
}
另外,存在另一種斷定傳遞給一個函數的參數數目的方法。這種特殊的方法多用了一點點技巧:我們利用了傳遞過來的任何參數值不可能為undefined這一事實。程式2-6展示一了個簡單的函數用來顯示一條錯誤訊息,如果沒有傳給它,則提供一條預設訊息。
程式2-6: 顯示錯誤訊息和預設訊息
function displayError( msg ) {
//檢查確保msg不是undefined
if ( typeof msg == 'undefined' ) {
//如果是,則設定預設訊息
msg = "An error occurred.";
}
//顯示訊息
alert( msg );
}
typeof語句的使用引入了類型檢查。因為JavaScript(目前)是一種動態類型語言,使得這個話題格外有用而重要的話題。有許多種方法檢查變數的類型;我們將探究兩種特別有用的。
第一種檢查物件類型的方式是使用顯式的typeof操作符。這種有用的方法給我們一個字串名稱,代表變數內容的類型。這將是一種完美的方案,除非變數的類型或者數組或自訂的對象如user(這時它總返回"ojbect",導致各種對象難以區分)。
這種方法的樣本見程式2-7
程式2-7. 使用typeof決定物件類型的樣本
//檢查我們的數字是否其實是一個字串
if ( typeof num == "string" )
//如果是,則將它解析成數字
num = parseInt( num );
//檢查我們的數組是否其實是一個字串
if ( typeof arr == "string" )
//如果是,則用逗號分割該字串,構造出一個數組
arr = arr.split(",");
檢查物件類型的第二種方式是參考所有JavaScript對象所共有的一個稱為constructor的屬性。該屬性是對一個最初用來構造此對象的函數的引用。該方法的樣本見程式2-8。
程式2-8. 使用constructor屬性決定物件類型的樣本
//檢查我們的數字是否其實是一個字串
if ( num.constructor == String )
//如果是,則將它解析成數字
num = parseInt( num );
//檢查我們的字串是否其實是一個數組
if ( str.constructor == Array )
//如果是,則用逗號串連該數組,得到一個字串
str = str.join(',');
表2-1顯示了對不同類型對象分別使用我所介紹的兩種方法進行類型檢查的結果。表格的第一列顯示了我們試圖找到其類型的對象。每二列是運行typeof Variable(Variable為第一列所示的值)。此列中的所有結果都是字串。最後,第三列顯示了對第一列包含的對象運行Variable.constructor所得的結果。些列中的所有結果都是對象。
表2-1. 變數類型檢查
———————————————————————————————
Variable typeof Variable Variable.constructor
———————————————————————————————
{an:"object"} object Object
["an","array"] object Array
function(){} function Function
"a string" string String
55 number Number
true boolean Boolean
new User() object User
——————————————————————————————————
使用表2-1的資訊你現在可以建立一個通用的函數用來在函數內進行類型檢查。可能到現在已經明顯,使用一個變數的constructor作為物件類型的引用可能是最簡單的類型檢查方式。當你想要確定精確吻合的參數數目的類型傳進了你的函數時,嚴格的類型檢查在這種可能會大有協助。在程式2-9中我們可以看到實際中的一例。
程式2-9. 一個可用來嚴格維護全部傳入函數的參數的函數
//依據參數列表來嚴格地檢查一個變數列表的類型
function strict( types, args ) {
//確保參數的數目和類型核匹配
if ( types.length != args.length ) {
//如果長度不匹配,則拋出異常
throw "Invalid number of arguments. Expected " + types.length +
", received " + args.length + " instead.";
}
//遍曆每一個參數,檢查基底類型
for ( var i = 0; i < args.length; i++ ) {
//如JavaScript某一項類型不符,則拋出異常
if ( args[i].constructor != types[i] ) {
throw "Invalid argument type. Expected " +
types[i].name +", received " +
args[i].constructor.name + " instead.";
}
}
}
//用來列印出使用者列表的一個簡單函數
function userList( prefix, num, users ) {
//確保prefix是一個字串,num是一個數字,
//且user是一個數組
strict( [ String, Number, Array ], arguments );
//迴圈處理num個使用者
for ( var i = 0; i < num; i++ ) {
//顯示一個使用者的資訊
print( prefix + ": " + users[i] );
變數類型檢查和參數長度校正本身是很簡單的概念,但是可用來實現複雜的方法,給開發人員和你的代碼的使用者提供更好的體驗。接下來,我們將探討JavaScript中的範圍以及怎麼更好的控制它。