B 2.5 JavaScript对象的反射机制
在普通的写代码过程中,程序员很清楚他正在使用的对象是怎样组成的,对象的属性以及方法是如何工作的。在某些时候,我们需要处理一些完全不了解的对象,而且需要在使用之前先研究他们特有的属性和方法。比方说,我们现在要完成一个生成日志或者调试的系统,我们可能就要面对一些未知的对象。这个过程成就是反射,对于Java和.NET程序员来书应该不陌生。
如果你想知道一个JavaScript对象是否支持某个属性或方法,我们可以象下面一样简单的测试一下:
if (MyObject.someProperty){
...
}
如果MyObject.someProperty被赋予布尔型的false或者,数字型的0,或者是null, 这种写法都会失败,所以我们要写一个更严密的测试:
if (typeof(MyObject.someProperty) != "undefined"){
如果我们关心属性的类型,我们也可以使用instanceof操作符,这个操作符可以识别基本的内嵌类型:
if (myObj instanceof Array){
...
}else if (myObj instanceof Object){
...
}
像其他类定义一样,我们也可以通过构造函数来定义:
if (myObj instanceof MyObject){
...
}
如果你非要用instanceof来测试一些自定义的类,那就要明白一些“要点”,首先,JSON不支持instanceof,因为再JSON中创建的所有东西不是JavaScript的对象就是数组;第二,内置对象支持内部继承。例如函数和数组,就都是从对象继承而来,所以对测试顺序会有影响。如果我们这样写:
function testType(myObj){
if (myObj instanceof Array){
alert("it's an array");
}else if (myObj instanceof Object){
alert("it's an object");
}
}
testType([1,2,3,4]);
并且把一个数组传进去,我们就可以得到正确的结果,这是一个数组,但是,如果我们这样写:
function testType(myObj){
if (myObj instanceof Object){
alert("it's an object");
}else if (myObj instanceof Array){
alert("it's an array");
}
}
testType([1,2,3,4]);
那我们就会得到这个一个对象的结果,在技术上这并没有什么问题,但是不是我们想要的结果。
最后,有时候我们会希望彻底的了解一个对象的所有属性以及方法,我们可以用以下这个简单的循环来实现:
function MyObject(){
this.color='red';
this.flavor='strawberry';
this.azimuth='45 degrees';
this.favoriteDog='collie';
}
var myObj=new MyObject();
var debug="discovering.../n";
for (var i in myObj){
debug+=i+" -> "+myObj[i]+"/n";
}
alert(debug);
这个循环会执行四次,返回在构造函数中已经赋过的值,for循环标记对内置对象也有效,在指向一个DOM节点的时候,上面的这个简单的调试循环会产生一个很大的弹出框。这种技术的另一个好的应用在第五章和第六章的例子中用到,用来实现观察者模式的用户接口。
在这里,还有另外一个传统的面向对象语言的特征需要指出一下,虚类和接口,下面让我们来看一下。