Programación en castellano
Inicio > Taller Web > Javascript > La historia del gato
-Artículos

La historia del gato

1 . El cuento del gato
2 . El prototipado

El cuento del gato fue originalmente contado 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, he 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.prototype.left = function(lng) {
  return this.substr(0,lng);
}

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

String.prototype.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.

 

Últimos comentarios
Últimos 5 comentarios

Espia Gatito Verde (14/11/2008)

Por
http://es.youtube.com/watch?v=3hp_hlNTEVI
http://www.gatov.blogspot.com/
http://profile.myspace.com/index.cfm?fuseaction=user.viewprofile&friendid=429335879&MyToken=2357b279-9adc-46cf-a846-8a5e3a7701a2

Objetos en JavaScript (19/07/2006)

Por
En java los objetos no se puede destruir. Solamente se puede eliminar sus propiedades y metos pero el Objeto sigue existiendo.

Urge Ayuda (26/07/2004)

Por
Hola pues al igual que ustedes no me funciono pero aprovecho que estoy aqui para realizarles una pregunta, tengo una pag con marcos (2) pero uno de ello el superior en el cual tengo el titulo de la pagina lo la dar un click sobre el lo puedes mover (error) lo cual no quiero que suceda como puedo bloquearlo al movimiento sin perder los links que ahi estan agradezco su ayuda...

No funciona (03/07/2003)

Por
Copie todo el codigo final del ejemplo del gato y lo comprobé, pero no funciono, al ejecutar sale el primer Miau!!, pero al dar click sobre el boton aceptar saca el siguiente error "error se esperaba un objeto" el error esta en la funcion: Maulla(), exactamente en la línea:
this.onMaulla();

Alguien ha solucionado el problema?
}

La Historia Del Gato. (04/04/2003)

Por
Porqué me da la impresión de que todos los que hacen buenos comentarios, lo hacen solo por hacerlo? No me lo van a creer, pero tengo muchos días queriendo hacer que funcione el tutorial y qué creen? pues! seguro que todos lo saben, pero nadie dice la verdad sobre La Historia Del Dichoso Gatito! Nooooo Funcionnaaaaa!!!! Tiene varios errores y no es justo que después de días llegue a la conclusión de que está mal escrito, o mal redactado, o la sintaxis es mala. Me quejo profundamente. Y mi comentario es que sería bueno que no dieran por entendido que todos los que leemos estos pequeños tutoriales, somos unos grandes programadores como los que hacen estos comentarios tan gratificantes para los autores del mismo. Si siguen así, no los van a dejar evolucionar en su carrera de programadores. Mejor será que ellos sepan que hay fallas y así podrían hacer más por los que estamos tratando de seguir adelante. Si ofendí a alguien pues lo siento mucho y ya qué!!!
 
Tienda
Patrocinados
 

Copyright © 1999-2007 Programación en castellano. Todos los derechos reservados.
Formulario de Contacto - Datos legales - Publicidad

Hospedaje web y servidores dedicados linux por Ferca Network

red internet: musica mp3 | logos y melodias | hospedaje web linux | registro de dominios | servidores dedicados
más internet: comprar | recursos gratis | posicionamiento en buscadores | tienda virtual | gifs animados