Zootropo

Diario del mundo geek.

martes, julio 27, 2004

Javascript: La herencia

Hay tres conceptos que son básicos para cualquier lenguaje de programación orientado a objetos: el encapsulamiento, la herencia y el polimorfismo. Aunque no estén soportados directamente por el lenguaje vamos a ver como podemos lograr estas tres cosas en Javascript. Empecemos por la herencia.

En un lenguaje orientado a objetos cuando establecemos que una clase (subclase) hereda de otra clase (superclase) estamos haciendo que la subclase contenga todas las propiedades y métodos que tenía la superclase.

Veamoslo con un ejemplo. Supongamos que queremos modelar los instrumentos musicales de una banda. Vamos a tener un tipo de objeto guitarra, otro tipo batería, bajo,... cada uno con sus propias propiedades y métodos, pero ocurre que puede que halla métodos y/o propiedades comunes a todos ellos por el hecho de ser instrumentos musicales, por ejemplo un método tocar. Podríamos crear un tipo de objeto instrumento que sería el que tuviera el método e indicar al programa que guitarra, batería y bajo son tipos de instrumentos, haciendo que hereden de instrumento y que obtengan todos sus propiedades y métodos (en este caso solo el método tocar).

En Javascript hay dos formas de implementar la herencia. La primera forma consiste en llamar al constructor del tipo padre dentro del constructor del tipo hijo. Abrimos el bloc de notas, escribimos lo siguiente y guardamos con extensión htm (no es un archivo html válido porque ni tan si quiera tenemos la etiqueta html o el body).

<script type="text/javascript">
//Constructores
function persona (nombre, dni){
this.nombre = nombre;
this.dni = dni;
this.toString = toString;
}

function alumno (nombre, dni, asignaturas){
this.heredar = persona;
this.heredar(nombre, dni);
this.asignaturas = asignaturas;
}

function profesor (nombre, dni, sueldo){
this.heredar = persona;
this.heredar(nombre, dni);
this.sueldo = sueldo;
}

//Otras funciones
function toString (){
return this.nombre + " " + this.dni;
}

//Inicio del programa
var pepe = new alumno("Pepe Botijos", 343234569, new Array("Matematicas", "Fisica", "Quimica"));
document.write(pepe.nombre + "<br/>");
document.write(pepe.dni + "<br/>");
document.write(pepe.asignaturas + "<br/>");
document.write(pepe.toString() + "<br/>");
</script>

En este ejemplo tenemos un tipo de objeto persona de la que heredan alumno y profesor (alumno y profesor son personas), por lo tanto estos dos subtipos tendrán las propiedades (nombre y dni) y los métodos (toString) que se hallan definido para el tipo persona, mas los que se definan en el subtipo (asignaturas en el caso del alumno y sueldo en el caso del profesor).

En este ejemplo hay un par de cosas que aún no habíamos visto, el hecho de que el operador + cuando actúa sobre cadenas, las concatena; y la función document.write que escribe un texto en el navegador. Además la palabra clave this, se refiere al objeto actual, de forma que this.toString() significa 'llama a la función toString del objeto actual' y this.sueldo significa la variable sueldo del objeto, en lugar de la variable sueldo que nos pasan como argumento.

La segunda forma de implementar la herencia se basa en la propiedad prototype, que existe por defecto para todos los objetos. Lo único que hay que hacer asignar a la propiedad prototype del tipo hijo el objeto padre.

function instrumento (){
this.tocar = tocar;
this.romper = romper;
}

function guitarra (){
}
guitarra.prototype = new instrumento();

function bateria (){
this.romper = romperBateria;
}
bateria.prototype = new instrumento();

function tocar (){
document.write("Estamos tocando musica<br/>");
}

function romper (){
document.write("Eso lo pagas tu<br/>");
}

function romperBateria (){
document.write("Rompiendo bateria, por favor espere.<br/>");
}

Esto funciona porque cuando se intenta acceder a una propiedad de un objeto, primero se comprueba si la propiedad existe entre las propiedades definidas para ese objeto. En el caso de que no se encuentre se comprueba si el objeto al que apunta la propiedad prototype tiene esa propiedad. En el caso de que este tampoco la tenga se comprueba para el objeto de la propiedad prototype de este y así sucesivamente (cada objeto tiene otro objeto que es su prototipo y hereda todas las propiedades de este).