La Güeb de Joaquín

Internet - JavaScript


Tutorial que explica como construir objetos en Javascript.


Sumario

Pequeño tutorial que explica como construir objetos, con propiedades, métodos y eventos, en Javascript. Para hacerlo de forma amena utiliza un cuento cuyo protagonista es un gato.
Éste documento lo encontré (hace 3 años) navegando por la red, lo copié porque me pareció interesante, aunque entendí bastante poco de lo que se describía en él. Ha pasado el tiempo y haciendo limpieza del disco duro he vuelto a leerlo y ahora además de entenderlo me ha parecido una joya así que lo trascribo tal y como lo copie para deleite y disfrute de todos.


El cuento del gato fue contado originalmente por Thomas Brattli en su tutorial Building a Crossbrowser DHTML library. Siempre he encontrado en él una manera estupenda de mostrar cómo se programan objetos en JavaScript y en general cómo funciona la programación orientada a objetos, y por supuesto, cada vez que lo he contado, lo he hecho de una manera diferente, e ido añadiendo y quitando cosas del "cuento" original, y cada vez que lo he contado, me han quedado las ganas de escribirlo.

Recientemente en el WEB-ES hemos tenido un pequeño jaleo con objetos, métodos y propiedades, así que pensé que si no lo escribía ahora no lo haría nunca... Así que allá va. Si a alguien le parece que puede añadirse o quitarse algo, o que no queda correctamente explicado, ¡escribeme!

El cuento del gato

Para construir un objeto gato en nuestro código javascript sólo tenemos que hacer una simple función:

function Gato() {
  return this;
}

Ya tendríamos un objeto gato en nuestro código, y sólo faltaría instanciarlo:

var Roger= new Gato();

El gato vacío, sin propiedades de ningún tipo, no nos sirve de mucho. De modo que vamos a darle una propiedad, que será su número de vidas. Es un gato a la española, o sea que tendrá siete vidas en vez de nueve. también le daremos un sonido para cuando maúlle.

function Gato() {
  this.vidas=7;
  this.sonido="Miau!!!!";
  return this;
}

De esta manera, habiendo usado el constructor anterior y teniendo un gato instanciado llamado Roger, podíamos decir

alert(Roger.sonido);

Y el resultado sería evidentemente éste.

Esto está muy bien cuando todas las instancias del objeto van a tener una propiedad con el mismo valor. Pero supongamos que queremos hacer gatos con distintos colores (lo que sería lo normal). Para ello podríamos pasarle el valor de una propiedad con un parámetro convencional. Algo como esto:

function Gato(color) {
  this.vidas=7;
  this.sonido="Miau!!!!";
  this.color=color;
  return this;
}

var Roger = new Gato("marron");

De esta manera nuestro gato Roger sería marrón.

Y otra vez estamos en las mismas: Tener un objeto que sólo tiene propiedades, puede llegar a ser útil, pero lo será mucho más si tiene métodos. Éstos le permitirán hacer cosas. ¿Cómo se hace un método? Un método es una función que se "endosa" al objeto y que hereda sus propiedades. Vamos a permitir que Roger maúlle:

function Gato(color) {
  this.vidas=7;
  this.sonido="Miau!!!!";
  this.color=color;
  this.maulla=Maulla;     
          //Fíjate en las mayúsculas, y también
          //en que Maulla no lleva paréntesis.
  return this;
}

function Maulla() {
  alert(this.sonido);
}

var Roger = new Gato("marron");
Roger.maulla();

Como luego quiero demostrar otra cosa, y además quiero complicar esto un poquito, vamos a darle otro método, que será el de arañar. Es más complicado: este método recibirá un parámetro, el cual será otro gato. Lo que hará este método es quitar una vida a otro gato, esto es, accederá a la propiedad vidas del otro gato y restará 1.

function Gato(color) {
  //objeto gato.
  //propiedades
  this.vidas=7;
  this.sonido="Miau!!!!";
  this.color=color;

  //metodos
  this.maulla=Maulla;
  this.arania=Arania;

  return this;
}

function Maulla() {
  //Metodo del objeto Gato
  alert(this.sonido);
}

function Arania(aQuien) {
  //Metodo del objeto Gato
  aQuien.vidas-=1;
}

var Roger = new Gato("marron");
var Michael = new Gato("amarillo");
Roger.arania(Michael);
alert(Michael.vidas);

Como habrás imaginado despues de esto, el pobre Michael sólo tendrá 6 vidas. Todavía tiene muchas, pero tampoco es como para alegrarse.

Te habrás fijado en que he colocado comentarios que dícen qué son métodos, qué propiedades, qué funciones son objetos y cuales métodos. Esto es así por que nuestro código comienza a hacerse grande. Es muy útil que hagas esto, cuando tengas un código de cientos de líneas, por mucho que lo conozcas, te acabarás perdiendo si no lo haces.

Y de nuevo estamos en las mismas. Nuestros gatos son ciegos y sordos. Quiero decir que, aunque nosotros sepamos que un gato maúlla, porque vemos el cartelito del alert, los otros gatos nunca sabrán de ninguna manera que otro gato ha maullado.¿Como hacemos para que cuando el gato maúlle o arañe los otros se enteren? A través de eventos. Se hacen añadiendo un método distinto... para el que no hace falta una función aparte. Será mejor si lo ves en el ejemplo:

function Gato(color) {
  //objeto gato.
  //propiedades
  this.vidas=7;
  this.sonido="Miau!!!!";
  this.color=color;

  //metodos
  this.maulla=Maulla;
  this.arania=Arania;
  
  //eventos
  this.onArania=new Function();
  this.onMaulla=new Function();

  return this;
}
function Maulla() {
  //Metodo del objeto Gato
  alert(this.sonido);
  this.onMaulla();
}

function Arania(aQuien) {
  //Metodo del objeto Gato
  aQuien.vidas-=1;
  this.onArania();
}

¡Es muy importante que al llamar al método que dispara el evento se llame al evento! De otra manera no servirá de nada. ¿cómo se usa esto? Bien, vamos a hacer que Michael tenga muy mala leche, y que cada vez que Roger maúlle, Michael lo arañe. Claro, el pobre Roger no es de piedra, y el pobre animalito, cuando es arañado, vuelve a maullar. Y claro, cuando Michael acaba con sus vidas, Roger muere (el objeto desaparece). Veamoslo, suponiendo el código anterior:

var Roger=new Gato("marron");
var Michael=new Gato("amarillo");

function RogerEsAraniado() {
  if (Roger.vidas>0) Roger.maulla();
  else Roger=null;
}

Roger.onMaulla=Michael.arania(Roger);
Michael.onArania=RogerEsAraniado();
    
Roger.maulla();

Verás que hay dos modos de activar el evento: o bien se escribe directamente el código correspondiente (Roger.onMaulla) o bien se llama a una función exterior pensada para manejar el evento (RogerEsAraniado) Las dos maneras son igual de válidas, pero deberás decantarte por la segunda si tienes que hacer condicionales, o, en general, cualquier cosa que exceda de una sola línea.

Finalmente ya has visto como destruir el objeto: basta con decir objeto=null. También puedes incluir un condicional dentro de la propia función que hace de objeto, incluyendo la línea:

if (lo que sea) this=null;

Y esa es la triiiiiiste historia del gato.

Tiene muchas aplicaciones, en realidad. Es una manera completamente distinta a la habitual en la que tienes un montón de funciones separadas que hacen cosas independientemente. Es una forma organizada y estructurada de trabajar, que te evitará muchos fallos y vicios de programación. Hay quien dice que es así como se debería de programar. Yo no creo en que deba hacerse así, pero siempre que se pueda, para un script complejo, creo que es una manera clara y útil de hacerlo.

Si quieres ver un ejemplo práctico de cómo llevar a cabo todo esto, puedes ver cómo he hecho la librería y verás que el resultado es mucho más claro que si hubiese habido 200 lineas de funciones independientes que no se comunicasen entre sí de ninguna manera.

¡Un abrazo!

El prototipado

Amablemente, me ha escrito Jaime Maimó del WEB-ES para completar en este minitutorial la parte del prototipado, que como vereis, puede ser muy útil a la hora de modularizar el código. Este es el mensaje que me ha enviado:

Esto del prototipado tiene la ventaja de que puedes ir definiendo funciones y añadiendolas como métodos de objetos, ya sean tuyos, o sean objetos "intrínsecos".

Un ejemplillo:

function paralelepipedo (x,y,z) {
  this.x=x;
  this.y=y;
  this.z=z;
}

Esta sería la función que crearía el/los objeto/s "paralelepipedo".

Ahora podremos añadir los métodos que queramos, sin tener que tocar para nada la función original, creando unas funciones independientes:

function variarEjeX(valor) {
  this.x+=valor;
}

function variarEjeY(valor) {
  this.y+=valor;
}

function variarEjeZ(valor) {
  this.z+=valor;
}

function volumen() {
  return this.x*this.y*this.x;
}

Y asociándolas a la función constructora, según:

paralelepipedo.prototype.nuevoX=variarEjeX;
paralelepipedo.prototype.nuevoY=variarEjeY;
paralelepipedo.prototype.nuevoZ=variarEjeZ;
paralelepipedo.prototype.cubicaje=volumen;

De este modo podremos manipular el objeto según:

var miobjeto=new paralelepipedo(2,3,4);

miobjeto.nuevoX(-1);
miobjeto.nuevoZ(2);
alert(miobjeto.cubicaje());
...

Donde más se usa el prototipado es para agregar funcionalidades a los objetos intrínsecos de JavaScript. Por ejemplo, ahí van unos prototipados para el objeto String:

String.prototipe.left = function(lng) {
  return this.substr(0,lng);
}

String.prototipe.right = function(lng) {
  return this.substr(this.length-lng,lng);
}

String.prototipe.trim = function() {
  return this.replace(/(^\s*)|(\s*$)/g,"");
}

De modo que si definimos una cadena de carácteres:

var prueba=" hay dos espacios en blanco al principio y uno al final ";

prueba.left(5) 
//nos dará " hay";
prueba.right(5) 
//nos dará "inal ";
prueba.trim() 
//nos dará "hay dos espacios en blanco al principio y uno al final";

Con lo que podemos enriquecer los objetos a voluntad.


Arriba

Referencia bibliográfica

© 1998-2000, Autores: José Luis Pumarega (info) y Jaime Maimo
publicado originalmente por Daniel Rodriguez y Joaquin Bravo.HTML en castellano.
Joaquin Medina Serrano

© 1997-2004 La Güeb de Joaquín - Apuntes Tácticos - Internet HTML

Creada.: Jueves, 22 de Enero de 2004

Actualizada.: 

[Arriba] [E-milio] [menu] [Home]


Esta página es española