|
|
Continuamos esta serie de artículos sobre la herencia de clases en JavaScript para webOS. Realmente trataremos de explicar el manejo de la herencia de forma práctica en Mojo, el framework de JavaScript utilizado en HP webOS.
En la parte 1 vimos la creación de clases y métodos de distintas formas. La más práctica es usando los mecanismos del framework Prototype.
Nota: Existen distintos tipos de mecanismos para trabajar la herencia de clases en JavaScript. La forma nativa es usando el prototipo de las funciones. Muchos piensan que es la mejor manera debido a que se usa una funcionalidad nativa del lenguaje y también porque facilita la legibilidad del código (con esto último no estoy de acuerdo). Mojo utiliza este mecanismo en los ejemplos que vienen en el SDK, pero también cuenta con el framework Prototype dentro de sus librerías. Personalmente prefiero este último mecanismo, que demuestra su justo valor en proyectos medianos y grandes donde el beneficio de la herencia de clases se hace más patente. También creo que es una manera más limpia de definir clases y métodos, y agrega alguna funcionalidad adicional que no es nativa del mecanismo de prototipos. Profundizaré en esto último en este artículo. Dicho todo esto, queda a elección del programador el mecanismo que quiera utilizar para conseguir sus fines.
Nota 2: JavaScript no tiene multi-herencia, aunque se las puede arreglar muy bien para simularla. Es un tema difícil y controvertido. Rara vez me he topado con la necesidad de crear una clase con varios padres. Lo cierto es que Prototype permite sólo un padre en la creación de una clase hija. Y en mi opinión, eso es acertado.
Parte 2: Llamadas a métodos de la clase padre, visibilidad de las propiedades y otras rutinas de uso común en herencia de clases.
Una clase hija no necesita llamar a métodos de la clase padre a menos que, en su definición, haya reescrito un método de ésta última. Hecho eso, es lícito que la clase hija pueda llamar al método dentro de la clase padre, y no el método propio. Para hacer eso, Prototype sugiere una forma muy ordenada:
ClasePadre = Class.create();
ClasePadre.addMethod({
metodo1 : function(a) { return a*a; }
});
ClaseHija = Class.create(ClasePadre);
ClaseHija.addMethod({
metodo1 : function($super,a,b) { return $super(a) * b; }
});
La clase hija claramente reescribe el metodo1, pero en su definición notamos cosas especiales:
- El primer parámetro es $super, que es una referencia del método de la clase padre que estamos reemplazando. Por eso es que la llamada $super(a) funciona, que es el método del padre.
- Es importante notar que en el uso del método de la clase hija NO es necesario inventarse un parámetro para poner en la posición de $super. Eso es automático!
- No es necesario que la nueva definición sea idéntica a la original. De aquí que hayamos agregado un parámetro nuevo b, como ejemplo.
Ejemplo de llamada al método de la clase hija:
a = new ClaseHija();
b = a.metodo1(2,3);
//en b se almacena 12.
Es importante mencionar que en los constructores de las clases hijas se recomienda llamar a los de las clases padres. El método especial que inicializa una clase en Prototype es initialize:
ClasePadre.addMethod({
initialize : function(value1) { this.value1 = value1; }
});
ClaseHija.addMethod({
initialize : function(value1,value2) {
$super(value1); //equivale a llamar al método initialize de la clase padre.
this.value2 = value2;
}
});
Ahora vamos a hablar de visibilidad de las propiedades. Ejemplo:
ClasePadre.Class.create({
privada : 0, //propiedad privada
initialize : function() {
this.publica = 1; //propiedad publica
}
});
ClasePadre.estatica = 2; //propiedad estática.
ClasePadre.addMethod({
privilegiada = function() { if (0 <= privada) this.publica = privada; }
});
Aqui vemos varios niveles de visibilidad:
- La variable "privada" sólo puede accederse desde dentro del código de ClasePadre. No es posible acceder a ella desde ninguna clase hija ni desde el exterior de la clase padre.
- La variable "publica" es visible desde todos los sitios. Es importante el uso del comando this.
- La variable "estatica" no es parte ninguna instancia ni de la clase padre ni de las clases hijas. Sólo es accesible através de la ClasePadre directamente: ClasePadre.estatica = 2;
Ahora os dejo varias rutinas interesantes para aplicarlas a objetos:
//retorna un arreglo con los nombres de las propiedades de un objeto:
function propertyNamesToArray(obj) {
var res = []; //arreglo inicial vacio
if (undefined == obj || null == obj) return res; //no es un objeto
for (var prop in obj) res.push(prop); //ciclo por las propiedades
return res;
}
//retorna TRUE si el objeto es una instancia de una clase con métodos definidos.
function hasMembers(obj) {
//based in http://phrogz.net/js/hasOwnProperty.html
var res = true;
try {
for(var prop in obj) {
if (obj.hasOwnProperty(prop)) return true;
}
return false;
} catch(e) {
res = false;
}
return res;
}
Nos vemos en la parte 3!