2009-02-12 102 views
10

我有:原型和构造对象属性

function Obj1(param) 
{ 
    this.test1 = param || 1; 

} 

function Obj2(param, par) 
{ 
    this.test2 = param; 

} 

现在,当我做:

Obj2.prototype = new Obj1(44); 
var obj = new Obj2(55); 

alert(obj.constructor) 

我:

function Obj1(param) { 
    this.test1 = param || 1; 
} 

但构造函数一直OBJ 2 .. 。 为什么? OBJ1已成为OBJ 2原型...

有人能解释我,详细,原型链和constructor属性

感谢

回答

25

constructor是原型对象的一个​​普通的属性(与DontEnum标志已设置,因此它不会出现在for..in循环中)。如果您替换原型对象,constructor属性也将被替换 - 有关更多详细信息,请参阅this explanation

您可以通过手动设置Obj2.prototype.constructor = Obj2来解决问题,但这种方式将不会设置DontEnum标志。

由于这些问题,依靠constructor进行类型检查并不是一个好主意:请使用instanceofisPrototypeOf()代替。


安德烈·费奥多罗夫问为什么new不会在constructor属性分配给实例对象,而不是问题。我想原因如下:

从相同的构造函数创建的所有对象共享构造函数属性,共享属性驻留在原型中。

真正的问题是JavaScript没有对继承层次结构的内置支持。周围有问题的几种方法(你是其中之一),“在精神”的JavaScript的另一个更将是以下几点:

function addOwnProperties(obj /*, ...*/) { 
    for(var i = 1; i < arguments.length; ++i) { 
     var current = arguments[i]; 

     for(var prop in current) { 
      if(current.hasOwnProperty(prop)) 
       obj[prop] = current[prop]; 
     } 
    } 
} 

function Obj1(arg1) { 
    this.prop1 = arg1 || 1; 
} 

Obj1.prototype.method1 = function() {}; 

function Obj2(arg1, arg2) { 
    Obj1.call(this, arg1); 
    this.test2 = arg2 || 2; 
} 

addOwnProperties(Obj2.prototype, Obj1.prototype); 

Obj2.prototype.method2 = function() {}; 

这使得多重继承小事为好。

9

检出Tom Trenka's OOP woth ECMAscript,即“继承”页面。 从原型的所有东西都是继承的,包括constructor属性。因此,我们必须别让它自己:

Obj2.prototype = new Obj1(42); 
Obj2.prototype.constructor = Obj2; 
1

好,constructor属性是像任何其他财产,在OBJ1的原型(属性)。如果你understand how prototypes work,这可能会有所帮助:

>>> obj.hasOwnProperty("constructor") 
false 

// obj's [[Prototype]] is Obj2.prototype 
>>> Obj2.prototype.hasOwnProperty("constructor") 
false 

// Obj2.prototype's [[Prototype]] is Obj1.prototype 
>>> Obj1.prototype.hasOwnProperty("constructor") 
true 

// Oh? 
>>> Obj1.prototype.constructor 
Obj1() 

啊哈!所以obj没有构造函数,JS去从[Obj1.prototype.constructor

一直到[[Prototype]]链上,我不知道为什么构造函数属性不是只设置在一个对象上当你使用'新'时。可能有一个原因,或者它可能只是一个疏忽。无论如何,我倾向于避免它。

+1

`constructor`之间的所有实例对象来自同一个构造函数创建了共享的属性,因此,把它放在原型中是正确的;只是JS没有内置的(深层)继承层次支持 - 我会给我的答案添加一个解释...... – Christoph 2009-02-12 14:10:29

3

简短版本:'构造函数'不符合你的想法,也不是跨浏览器兼容的。切勿使用它。

龙版本:Convention for prototype inheritance in JavaScript

一般:你感到困惑,由于(一)间的阻抗不匹配基于类和基于原型的OO,和(b)JavaScript的特定的比较差解释的陌生感基于原型的面向对象。

如果您发现您喜欢并且坚持的原型实现,您可能会更高兴。许多图书馆都有一个。这里的任意一个我用:

Function.prototype.subclass= function() { 
    var c= new Function(
     'if (!(this instanceof arguments.callee)) throw(\'Constructor called without "new"\'); '+ 
     'if (arguments[0]!==Function.prototype.subclass.FLAG && this._init) this._init.apply(this, arguments); ' 
    ); 
    if (this!==Object) 
     c.prototype= new this(Function.prototype.subclass.FLAG); 
    return c; 
} 
Function.prototype.subclass.FLAG= new Object(); 

而且这里有一个可以如何使用它的一个例子:

// make a new class 
var Employee= Object.subclass(); 

// add members to it 
Employee.prototype._LEGS= 2; 
Employee.prototype.getLegs= function() { 
    return this._LEGS; 
}; 

// optional initialiser, takes arguments from constructor 
Employee.prototype._init= function(name) { 
    this.name= name; 
}; 

// make a subclass 
Manager= Employee.subclass(); 

// extend subclass method 
Manager.prototype._init= function(name, importance) { 
    // call base class's method 
    Employee.prototype._init.call(this, name); 
    this.importance= importance; 
} 

// all managers are well-known to have three legs 
Manager.prototype._LEGS= 3; 

// create one 
var jake= new Manager('Jake the Peg', 100);