JavaScript面向对象的支持(5)

发表于:2007-07-01来源:作者:点击数: 标签:
八、JavaScript 面向对象 的支持 ~~~~~~~~~~~~~~~~~~ (续) 4). 需要用户维护的另一个属性:constructor ------ 回顾前面的内容,我们提到过: - (如果正常地实现继承模型,)对象实例的constructor属性指向构造器 - obj.constructor.prototype指向该对象的原

八、JavaScript面向对象的支持
~~~~~~~~~~~~~~~~~~
(续)

 4). 需要用户维护的另一个属性:constructor
 ------
 回顾前面的内容,我们提到过:
   - (如果正常地实现继承模型,)对象实例的constructor属性指向构造器
   - obj.constructor.prototype指向该对象的原型
   - 通过Object.constructor属性,可以检测obj2与obj1是否是相同类型的实例

  与原型链要通过用户代码来维护prototype属性一样,实例的构造器属性constructor也需要用户代码维护。

  对于JavaScript的内置对象来说,constructor属性指向内置的构造器函数。如:
//---------------------------------------------------------
// 内置对象实例的constructor属性
//---------------------------------------------------------
var _object_types = {
  @#function@#  : Function,
  @#boolean@#   : Boolean,
  @#regexp@#    : RegExp,
// @#math@#     : Math,
// @#debug@#    : Debug,
// @#image@#    : Image;
// @#undef@#    : undefined,
// @#dom@#      : undefined,
// @#activex@#  : undefined,
  @#vbarray@#   : VBArray,
  @#array@#     : Array,
  @#string@#    : String,
  @#date@#      : Date,
  @#error@#     : Error,
  @#enumerator@#: Enumerator,
  @#number@#    : Number,
  @#object@#    : Object
}

function objectTypes(obj) {
  if (typeof obj !== @#object@#) return typeof obj;
  if (obj === null) return @#null@#;

  for (var i in _object_types) {
    if (obj.constructor===_object_types[i]) return i;
  }
  return @#unknow@#;
}

// 测试数据和相关代码
function MyObject() {
}
function MyObject2() {
}
MyObject2.prototype = new MyObject();

window.execScript(@#@#+
@#Function CreateVBArray()@# +
@#  Dim a(2, 2)@# +
@#  CreateVBArray = a@# +
@#End Function@#, @#VBScript@#);

document.writeln(@#<div id=dom style="display:none">dom<@#, @#/div>@#);

// 测试代码
var ax = new ActiveXObject("Microsoft.XMLHTTP");
var dom = document.getElementById(@#dom@#);
var vba = new VBArray(CreateVBArray());
var obj = new MyObject();
var obj2 = new MyObject2();

document.writeln(objectTypes(vba), @#<br>@#);
document.writeln(objectTypes(ax), @#<br>@#);
document.writeln(objectTypes(obj), @#<br>@#);
document.writeln(objectTypes(obj2), @#<br>@#);
document.writeln(objectTypes(dom), @#<br>@#);

在这个例子中,我们发现constructor属性被实现得并不完整。对于DOM对象、ActiveX对象来说这个属性都没有正确的返回。

确切的说,DOM(包括Image)对象与ActiveX对象都不是标准JavaScript的对象体系中的,因此它们也可能会具有自己的constructor属性,并有着与JavaScript不同的解释。因此,JavaScript中不维护它们的constructor属性,是具有一定的合理性的。

另外的一些单体对象(而非构造器),也不具有constructor属性,例如“Math”和“Debug”、“Global”和“RegExp对象”。他们是JavaScript内部构造的,不应该公开构造的细节。

我们也发现实例obj的constructor指向function MyObject()。这说明JavaScript维护了对象的constructor属性。——这与一些人想象的不一样。

然而再接下来,我们发现MyObject2()的实例obj2的constructor仍然指向function MyObject()。尽管这很说不通,然而现实的确如此。——这到底是为什么呢?

事实上,仅下面的代码:
--------
function MyObject2() {
}

obj2 = new MyObject2();
document.writeln(MyObject2.prototype.constructor === MyObject2);
--------
构造的obj2.constructor将正确的指向function MyObject2()。事实上,我们也会注意到这种情况下,MyObject2的原型属性的constructor也正确的指向该函数。然而,由于JavaScript要求指定prototype对象来构造原型链:
--------
function MyObject2() {
}
MyObject2.prototype = new MyObject();

obj2 = new MyObject2();
--------
这时,再访问obj2,将会得到新的原型(也就是MyObject2.prototype)的constructor属性。因此,一切很明了:原型的属性影响到构造过程对对象的constructor的初始设定。

作为一种补充的解决问题的手段,JavaScript开发规范中说“need to remember to reset the constructor property@#,要求用户自行设定该属性。

所以你会看到更规范的JavaScript代码要求这样书写:
//---------------------------------------------------------
// 维护constructor属性的规范代码
//---------------------------------------------------------
function MyObject2() {
}
MyObject2.prototype = new MyObject();
MyObject2.prototype.constructor = MyObject2;

obj2 = new MyObject2();


更外一种解决问题的方法,是在function MyObject()中去重置该值。当然,这样会使得执行效率稍低一点点:
//---------------------------------------------------------
// 维护constructor属性的第二种方式
//---------------------------------------------------------
function MyObject2() {
  this.constructor = arguments.callee;
  // or, this.constructor = MyObject2;

  // ...
}
MyObject2.prototype = new MyObject();

obj2 = new MyObject2();

 

[1]    

原文转自:http://www.ltesting.net