其他面向对象语言的一个常见特性是,能够根据传入的不同数量或类型的参数,通过“重载(overload)”函数来发挥不同的功用。尽管这个特性在JavaScript中并没有被直接支持,也有很多种办法能够实现。
函数重载(function overloading)必须依赖两件事情:传入参数的数量和传入参数的类型。
JavaScript中每个函数都带有一个仅在这个函数范围作用的变量(contextual variable)成为 arguiments,它是一个包含所有传给函数的参数的伪数组(pseudo-array),它不是一个真正意义上的数组,不能修改它,也不能用 push() 来添加元素,但可以访问其中的元素,也具有 length 属性。
// 发送一条信息的简单函数 function sendMessage( msg, obj ) { // 如果消息和对象(的参数)都被提供 if ( arguments.length == 2 ) // 给对象发送消息 obj.alert( msg ); // 否则,假定只提供了一条消息 else // 那么仅显示默认的错误信息 alert( msg ); } // 仅用一个参数调用这个函数,用 alert 来显示此消息 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,可以利用这个特性来做判断。例如:实现这样一个简单函数,它用于显示错误信息,如果没有提供信息的内容,就显示默认的信息。
function displayError( msg ) { // 检查并确认 msg 是否 undefined if ( typeof msg == 'undefined' ) { // 如果是,则置 msg 为默认信息 msg = "An error occurred."; } // 显示该消息 alert( msg ); }
如果有参数传递进来,可以使用两种方法来判断变量的类型:第一种方法是使用 typeof 操作符。它提供了一个字符串名称,用来表达变量内容的类型。当变量不是 object 或者 array 类型时,这应该是最完美的解决办法了。但对于自定义对象它只返回object,很难与其它的object区分开来:
// 检查我们的数字是否实际是字符串 if ( typeof num == "string" ) // 若是,则根据这个字符串解析出整数来 num = parseInt( num ); // 检查我们的数组是否实际上是字符串 if ( typeof arr == "string" ) // 若是,则根据逗号切分出数组来 arr = arr.split(",");
第二种判断传入参数类型的方法是所有JavaScript对象都带有 constractor 属性,这个属性引用的是原本用来构造该对象的那个函数:
// 检查我们的数字是否实际是字符串 if ( num.constructor == String ) // 若是,则根据这个字符串解析出整数来 num = parseInt( num ); // 检查我们的数组是否实际上是字符串 if ( str.constructor == Array ) // 若是,则根据逗号切分出数组来 str = str.join(',');
用下表对不同类型对象进行类型检查的结果。第一列是尝试判断类型的对象;第二列是执行typeof的结果,结果是字符串;第三列是constructor属性的结果,结果都是对象
变量 |
typeof变量 |
变量.constructor |
{an:"object"} |
object |
Object |
["an","object"] |
object |
Array |
Function(){} |
function |
Function |
"a string" |
string |
String |
55 |
number |
Number |
true |
boolean |
Boolean |
new User() |
object |
User |
很明显,通过 constructor 属性进行类型检查是最不容易犯错的方法。例如,写一个函数判断传入函数的参数是否有正确的数量和类型:
// 用一个变量类型列表严格检查一个参数列表
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++ ) {
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 是数字,users 是数组
strict( [ String, Number, Array ], arguments );
// 遍历 ‘num’ 个用户
for ( var i = 0; i < num; i++ ) {
// 显示每个用户的信息
alert( prefix + ": " + users[i] );
}
}
[/code]
转载请注明:陈童的博客 » JavaScript的语言特性 — 函数重载和类型检查