2009年9月13日星期日

[note]面向对象的Javascript:函数重载和类型检查

其它面向对象的语言(比如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-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中的作用域以及怎么更好的控制它。

没有评论: