2009-09-28 15 views
8

Estoy haciendo programación orientada a objetos en JavaScript sin Prototype/jQuery (uso jQuery para otras cosas). Hasta ahora ha funcionado bien, pero tuve un problema con la herencia. Básicamente, cuando declaro objetos en un constructor, se comparten entre instancias. A continuación se muestra un código de ejemplo:Herencia de Javascript: ¿los objetos declarados en el constructor se comparten entre instancias?

A = function() 
    { 
     this.y = new Array(); 
    } 

    A.prototype.doStuff = function(n) 
    { 
     this.y.push(n); 
    } 

    B = function() 
    { 
    } 

    B.prototype = new A(); 

    var b1 = new B(); 
    var b2 = new B(); 

    b1.doStuff(100); 
    b2.doStuff(200); 

    console.log("b1:"); 
    console.log(b1); 
    console.log("b2:"); 
    console.log(b2); 

Esto da salida a una serie [100, 200] tanto para b1 y b2. Lo que quiero es que b1 y b2 tengan sus propias matrices separadas para y. ¿Cómo hago esto?

(PS. Asumo que el sistema de la clase de los Prototipos ha construido algo en esto. Sin embargo, yo preferiría no volver a escribir un montón de código para utilizar ese sistema de clases)

Respuesta

7

El problema es que su función de constructor A solo se ejecuta una vez para todas las instancias B, por lo que this.y es una referencia a una sola matriz. Cualquier referencia al mismo desde B se resolverá a través de la cadena de prototipos a la única referencia central A, que solo tiene una y. Esta es una característica muy útil, simplemente no para lo que estás tratando de hacer aquí.

La respuesta es separar la construcción de la inicialización; el constructor configura los recursos centrales y el inicializador inicializa una instancia. Así es como la mayoría de las implementaciones de "clase" que he visto para JavaScript controlan el problema. Para que esto funcione, debe proporcionar un medio para que cada nivel de la jerarquía invoque el inicializador del nivel anterior (que también es útil para otros métodos), por ejemplo, supercalls.

Supercalls son por eso que es probablemente mejor usar algo como prototipo para esto: Son difíciles de hacer bien, y es muy fácil caer en el "nieto" problema - una solución que parece funcionar , pero termina trabajando solo con un elemento primario < - Estructura de hijos, no un elemento principal < - Hijo < - Estructura de GrandChild.

Sin embargo, si vas a hacer tu propio mecanismo de herencia, this post on supercalls de mi blog patéticamente anémico puede ser útil ya que profundizo en algunos de esos temas. Toma una versión simplificada del mecanismo de herencia de Prototype, la deconstruye un poco, y habla de una forma de hacer supercalls que no tiene algunos problemas que tengo con las supercapas actuales de Prototype. Eso puede ayudarte a hacerlos en tu propio mecanismo.

+1

Sí, terminé haciendo algo como lo que describiste en tu publicación de blog. Básicamente, tengo una función 'construct (target)' separada que inicializa variables específicas de instancia para 'target'. Los niños llaman esto a su súper clase. No es particularmente bonito, pero parece funcionar. –

2
B.prototype = new A(); 

esto crea sólo una instancia de Una para cada B.

Se podría pensar en hacer algo como

B = function() 
{ 
    this.$super = new A(); 
} 


B.prototype.doStuff = function() 
{ 
    return this.$super(args); 
} 


C = function() 
{ 
    this.$super = new B(); 
} 


C.prototype.doStuff = function() 
{ 
    return this.$super(args); 
} 

C.prototype.whoIsMyGrandParent = function() 
{ 
    return this.$super.$super; 
} 

Javascript NO verdadera inheritation

+0

Eso sufre de lo que yo llamo el problema del "nieto": tan pronto como haya una "C" derivada de "B", ya no funcionará, porque no hay forma de que "B" se refiera a ' A'. (Además, FWIW, 'super' es una palabra reservada en JavaScript.) –

+0

lo siento, eso es correcto. Usé $ super en mis scripts. No veo su problema de nieto. – jantimon

+1

Javascript tiene herencia. Simplemente no es herencia clásica. Prototypal OO es una forma completamente diferente, pero totalmente legítima, de OO. – eyelidlessness

Cuestiones relacionadas