2012-01-04 9 views
6

Estoy tratando de aplicar herencia prototipada a una función en Javascript. Todo es bastante simple e incluso se describe en Wikipedia's javascript lemma. Funciona si mis propiedades son tipos simples javascript:javascript prototyped inheritance and object properties

function Person() { 
    this.age = 0; 
    this.location = { 
     x: 0, 
     y: 0, 
     absolute: false 
    }; 
}; 

function Employee() {}; 

Employee.prototype = new Person(); 
Employee.prototype.celebrate = function() { 
    this.age++; 
} 

var pete = new Employee(); 
pete.age = 5; 
pete.celebrate(); 
var bob = new Employee(); 
bob.celebrate(); 
console.log("bob is " + bob.age + " pete is " + pete.age); 

Con Employee.prototype = new Person();, todas las propiedades de la persona y (prototipos) métodos son heredados por los empleados, que es fundamental para la herencia.

Esto funciona como se esperaba: bob is 1 pete is 6

Ahora estoy empezando a jugar con la ubicación de Pete (después de celebrar)

pete.celebrate(); 
pete.location.absolute=true; 

Viendo bob.location.absolute muestra: true, que está contraindicado intuitiva (No toqué la ubicación de Bob, así que espero que tenga el valor inicial declarado en Person) y arruine mi solución.

En mi comprensión inicial esto debería haber sido falso. Me doy cuenta de que probablemente debería clonar el objeto de ubicación de la persona inicial, pero no estoy seguro de dónde o cómo hacerlo. Y si hay quizás mejores técnicas para la herencia?

Respuesta

3

Cuando se crea una instancia de un nuevo empleado, se copian todas las propiedades de la persona. Como esta es una copia superficial, pete y bob comparten el mismo objeto de ubicación. Para su problema, no parece una muy buena solución. También se puede usar un marco o hacer un corte como este:

function Employee() { Person.apply(this); }; 

Esto llama al constructor Persona en el contexto de la presente objeto.

El MDC tiene más información sobre esto: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/apply

3

no ejecute el constructor Person al heredar, un Employee no siquiera debería tener un .location porque no es en Person.prototype.

function createObject(fn){ 
    function f(){} 
    f.prototype = fn.prototype; 
    return new f; 
} 

continuación:

Employee.prototype = createObject(Person); 

Este heredará correctamente sin efectos secundarios (constructor de funcionamiento).

Usted sólo ejecutar el constructor de los padres en el constructor del niño:

function Employee() { 
Person.apply(this, arguments); 
} 
+0

¿Cuál es la ventaja de usar createObject (Person) en lugar de nueva Person()? Solo agrega una capa de prototipo de indirección. – Kosta

+0

@Kosta para evitar los efectos secundarios de ejecutar un constructor al heredar. Los constructores usualmente tienen un código de inicialización que no quieres ejecutar cuando no estás instanciando nada. un 'nuevo empleado' seguirá siendo' instancia de persona' porque tanto 'Person.prototype' como' f.prototype' apuntan al mismo objeto. – Esailija

+0

Pero todavía está ejecutando el constructor en createObject() (una vez). Además, está ejecutando el constructor en Employee() (en cada creación de instancias). ¿Podría dar un ejemplo donde createObject() es útil? – Kosta

0

me encontré con problema similar. Terminé usando un constructor separado para el objeto interno.

function engine(cc, fuel) { 
     this.cc = cc; 
     this.fuel = fuel 
} 

function car(type, model, cc, fuel) { 
     this.type = type; 
     this.model = model; 
     this.engine = new engine(cc, fuel); 
} 


var mycar = new car("sedan", "toyota corolla", 1500, "gas"); 
console.log(mycar.type); 
//sedan 
console.log(mycar.engine.cc); 
//1500 

Si tuviera cualquier método de los prototipos de 'motor' o constructores de automóviles, todavía estarían disponibles. Sin embargo, no estoy derivando la clase "coche" de la clase "motor" en sentido OOP. No era necesario. El "motor" se utiliza como un componente de "automóvil".

Mientras tanto, por herencia, prefiero usar los nuevos métodos incorporados en ECMAScript 5, lo que significa usar Object.create, Object.defineProperties, etc. Se admiten incluso en IE9. Antes de eso, utilicé el mismo método 'apply()' sugerido por Kosta.