一个对象如何知道是哪个函数构造的它呢?通过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属性的具体位置,是在对象里还是在原型里。
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不可靠,因为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();
这样生成的对象就正常了。
假设有一条这样的语句:
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也不好使了。