2012-07-26 12 views
11

Estoy diseñando una jerarquía de clases en JavaScript. Hasta ahora funciona bien, pero no veo cómo determinar si un objeto es una "instancia" de una clase principal. Ejemplo:javascript oop, instanceof y clase base

function BaseObject(name){ 
    this.name = name; 

    this.sayWhoAmI = function(){ 
     console.log(this.name + ' is a Derivation1 : ' + (this instanceof Derivation1)); 
     console.log(this.name + ' is a Derivation2 : ' + (this instanceof Derivation2)); 
     console.log(this.name + ' is a BaseObject : ' + (this instanceof BaseObject)); 
    }; 
} 
function Derivation1(){ 
    BaseObject.apply(this, ['first derivation']); 
} 
function Derivation2(){ 
    BaseObject.apply(this, ['second derivation']); 
} 

var first = new Derivation1(); 
var second = new Derivation2(); 

first.sayWhoAmI(); registros de esto:

first derivation is a Derivation1 : true 
first derivation is a Derivation2 : false 
first derivation is a BaseObject : false 

mientras second.sayWhoAmI(); registra esto:

second derivation is a Derivation1 : false 
second derivation is a Derivation2 : true 
second derivation is a BaseObject : false 

Siento que tanto first y second objeto debe tener decir que son casos de BaseObject.

Entiendo que JavaScript puede no estar hecho para esto, pero me pregunto si hay una forma de lograrlo.

+6

Sólo llamar 'Base.apply (...)' ¿no herencia de configuración. Tienes que configurar el prototipo correctamente. Ver: http://jsfiddle.net/fkling/wJE6s/. También eche un vistazo a esta pregunta para obtener una explicación: http: // stackoverflow.com/questions/3145700/javascript-inheritance-instanceof-not-working? rq = 1 –

+1

Félix debe escribir esto como respuesta, eso es exactamente lo que necesito y su violín lo demuestra de manera simple. ¡No dejes que otra persona te robe tu reputación! – Johnny5

+0

De acuerdo, debería agregar una respuesta, pero probablemente no esté preocupado por aumentar su representante en .01%. – jahroy

Respuesta

10

Solo llamando a Base.apply(...) no configura la herencia. Todo lo que hace .apply es establecer this en el primer argumento, nada más. Es importante llamar al constructor padre, pero no es suficiente.

Lo que tienes que hacer es configurar correctamente la cadena del prototipo. Es decir, debe establecer Derivation1.prototype en algo que herede de Base.prototype.

Dado que cada instancia de una función constructora hereda desde el prototipo de las funciones constructoras, verá código como

Derivation1.prototype = new Base(); 

Ésta es una mala idea y ya se puede ver por qué: Base espera argumentos para establecer hasta propiedades específicas de instancia (name en este caso). Pero no nos importan estas propiedades, ya que las estamos inicializando más adelante en el constructor hijo con Base.apply(this, ...).

Así que todo lo que necesitamos es un objeto que hereda de Base.prototype y por suerte, ECMAScript 5 define una función que puede hacer eso por nosotros (polyfill):

Derivation1.prototype = Object.create(Base.prototype); 

Esto crea un nuevo objeto que hereda de Base.prototype. Ahora, puesto que se ha sustituido el prototipo original con un nuevo objeto, hay que establecer la propiedad constructor de manera que apunte correctamente a Derivation1:

Derivation1.prototype.constructor = Derivation1; 

A continuación se muestra un ejemplo completo. También eche un vistazo a this fiddle y this excellent answer by T.J. Crowder, lo que explica básicamente los mismos problemas, pero tal vez de una mejor manera.


Ejemplo:

function BaseObject(name){ 
    this.name = name; 
} 

// move properties shared by all instances to the prototype! 
BaseObject.prototype.sayWhoAmI = function() { 
    console.log(this.name + ' is a Derivation1 : ' + (this instanceof Derivation1)); 
    console.log(this.name + ' is a Derivation2 : ' + (this instanceof Derivation2)); 
    console.log(this.name + ' is a BaseObject : ' + (this instanceof BaseObject)); 
}; 

function Derivation1(){ 
    BaseObject.apply(this, ['first derivation']); 
} 

Derivation1.prototype = Object.create(BaseObject.prototype); 
Derivation1.prototype.constructor = Derivation1; 

// some useless method of the child "class" 
Derivation1.prototype.someOtherMethod = function() { 
    return 42; 
}; 

var first = new Derivation1(); 
first.sayWhoAmI();