ITEEDU

javascript面向对象设计-深入constructor属性

constructor属性

一个对象如何知道是哪个函数构造的它呢?通过constructor属性可以知道。

// 等价于 var foo = new Array(1, 56, 34, 12);  
var arr = [1, 56, 34, 12];  
alert(arr.constructor === Array); // true 

// 等价于 var foo = new Function();  
var Foo = function() { };  
alert (Foo.constructor === Function); // true  

// 由构造函数实例化一个obj对象  
var obj = new Foo();  
alert (obj.constructor === Foo); // true   
// 将上面两段代码合起来,就得到下面的结论  
alert (obj.constructor.constructor === Function); // true

constructor属性的由来

那constructor属性是怎么来的呢?要想弄清这个问题就要知道constructor属性的具体位置,是在对象里还是在原型里。

var p=new function(){};
alert(p.hasOwnProperty('constructor'));//false
alert(p.__proto__.hasOwnProperty('constructor'));//true

hasOwnProperty方法是来判定对象是否包含指定名称的属性,不会向原型链搜索。要想搜索原型链可以用in关键字('constructor' in obj)。 由上面代码可知constructor属性是对象原型中的属性。我们再来做一个测试就更清楚了。

function Person(name) {};  
alert(Person.prototype.constructor===Person);//true

函数对象的prototype最终会成为对象的原型,其constructor自然也就是对象原型的一部分,这样obj. constructor自然也是成立的。可以参见new关键字的作用

不可靠的constructor

为什么说constructor不可靠,因为prototype是可改变的,在用原型模拟继承时这是经常的事。

function ClassA(){}
function ClassB(){}
ClassB.prototype=new ClassA();
var obj=new ClassB();
alert(obj.constructor===ClassB);//false
alert(obj.constructor===ClassA);//true
alert(obj.__proto__ instanceof ClassA);//true
alert(obj.__proto__.hasOwnProperty('constructor'));//false
alert(obj.__proto__.__proto__.hasOwnProperty('constructor'));//true

为什么obj的constructor跑到了原型的原型中?

obj的原型是new ClassA(),是没有constructor属性的,ClassA的prototype没有改变是有constructor属性的,所以new ClassA()的对象的原型是有constructor属性的,所以constructor属性就到了原型的原型中了。

所以要想用constructor属性来判定对象类型,就要手工设置其constructor属性。

function ClassA(){}
function ClassB(){}
ClassB.prototype=new ClassA();
ClassB.prototype.constructor=ClassB;
var obj=new ClassB();

这样生成的对象就正常了。

instanceof关键字也不可靠

假设有一条这样的语句:

obj instanceof ClassA;

在上面的语句执行过程中,虚拟机会把ClassA.prototype和obj的_proto_链上的节点逐个进行比较,如果找到相等的节点,则返回true,否则返回false。

function ClassA(){}
function ClassB(){}
function ClassC(){}
ClassB.prototype=new ClassA();
var obj=new ClassB();
alert(obj instanceof ClassB);//true
alert(obj instanceof ClassA);//true
ClassB.prototype={};
alert(obj instanceof ClassB);//false

由于ClassB改了prototype属性,所以instanceof也不好使了。