2009-02-12 15 views
10

tengo:prototipo y constructor de propiedades del objeto

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

} 

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

} 

ahora cuando lo haga:

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

alert(obj.constructor) 

tengo:

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

pero la función constructora ha sido Obj2 .. . ¿por qué eso? Obj1 se ha convertido en el prototipo Obj2 ...

Puede alguien explicar, en detalle, la cadena de prototipos y la propiedad constructor

Gracias

Respuesta

25

constructor es una característica regular del objeto prototipo (con la DontEnum bandera establecida para que no aparezca en for..in bucles). Si reemplaza el objeto prototipo, también se reemplazará la propiedad constructor; consulte this explanation para obtener más detalles.

Puede solucionar el problema configurando manualmente Obj2.prototype.constructor = Obj2, pero de esta forma, la bandera DontEnum no se configurará.

Debido a estos problemas, no es una buena idea confiar en constructor para comprobar el tipo: use instanceof o isPrototypeOf() en su lugar.


Andrey Fedorov planteó la pregunta de por qué new él no se asigna la propiedad constructor al objeto de instancia en su lugar. Supongo que la razón para esto está en las siguientes líneas:

Todos los objetos creados a partir de la misma función de constructor comparten la propiedad del constructor, y las propiedades compartidas residen en el prototipo.

El problema real es que JavaScript no tiene soporte integrado para las jerarquías de herencia. Hay varias maneras de evitar el problema (el suyo es uno de ellos), otro más 'en el espíritu' de JavaScript sería el siguiente:

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() {}; 

Esto hace herencia múltiple trivial también.

9

Consulte Tom Trenka's OOP woth ECMAscript, la página "Herencia". Todo del prototipo se hereda, incluida la propiedad constructor. Por lo tanto, tenemos que unbreak nosotros mismos:

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

Bueno, la propiedad constructor es una propiedad como cualquier otro, en el prototipo (propiedad) de Obj1. Si understand how prototypes work, esto podría ayudar:

>>> 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() 

Aha! Entonces obj no tiene constructor, JS lo sube por la cadena [[Prototype]], todo el camino desde Obj1.prototype.constructor

No estoy seguro de por qué la propiedad del constructor no está solo en un objeto cuando usas `nuevo '. Puede haber una razón, o podría ser un descuido. De cualquier manera, tiendo a evitarlo.

+1

'constructor' es una propiedad que es compartida entre todas las instancias objetos creados a partir del mismo constructor, por lo tanto, es lo correcto para ponerlo en el prototipo; Es solo que JS no tiene soporte integrado para las jerarquías de herencia (profundas). Agregaré una explicación a mi respuesta ... – Christoph

3

Versión corta: 'constructor' no hace lo que usted piensa, y no es compatible con varios navegadores. Nunca lo use

Versión larga: Convention for prototype inheritance in JavaScript

general: están consiguiendo confundido debido a (a) la falta de coincidencia de impedancia entre y OO basado en prototipos, y (b) la extrañeza de especial interpretación bastante pobre de JavaScript del basada en clases prototipo de OO.

Probablemente será más feliz si encuentra una implementación de clases en prototipos que le guste y quédese con eso. Muchas bibliotecas tienen una. He aquí un arbitraria que utilizo:

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(); 

Y aquí está un ejemplo de cómo se puede utilizar:

// 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); 
Cuestiones relacionadas