Web BizarroWeb Bizarro

Suscríbete a nuestro Newsletter

X

Únete a nuestra lista de correos para recibir semanalmente actualizaciones de nuestro contenido.

POO en JavaScript Herencia

POO en JavaScript Herencia 31.JAN.14

Alvaro José Rios Ch
Fundador WebBizarro

Espero que nos hayan seguido en esta serie de tutoriales sobre programación orientada a objetos si no es así deberías ver los dos primeros antes de continuar con este.

Programación orientada a objetos con JavaScript

POO en JavaScript (Encapsulación) 

Esta es la última parte de nuestro tutorial de POO en JavaScript en el cual hablaremos sobre herencia, y este es uno de los conceptos que pueden causar un poco de confusión en JavaScript. En otros lenguajes tenemos las clases y para heredar solo tenemos que colocar extends o algo parecido, pero el lenguaje JavaScript no nos permite hacer esto por lo que debemos buscar otros métodos para construir el concepto de herencia y hay muchas formas de hacerlo, nosotros nos concentraremos en una, Parasitic Combination Inheritance o herencia por combinación parasitaria, y si se que suena un poco raro pero ya iremos viendo de que se trata.

Anteriormente creamos un objeto usuario que almacenaba sus datos y las notas que obtenía en un examen ahora implementaremos la herencia creando una pequeña aplicación de examen.

Pero porque debemos usar herencia en JavaScript, la respuesta es sencilla menos trabajo, si hacemos código reutilizablepodemos aprovechar la herencia para no tener que repetirlo y evitar la fatiga como diría el doctor Chapatin.

Primero vamos a revisar un modelo de creación de objetos basado en lo que ya vimos anteriormente, este método fue creado por Douglas Crockford.

if (typeof Object.create !== 'function') {
    Object.create = function (o) {
        function F() {
        }
        
        F.prototype = o;
        return new F();
    };
}


El método Object.create fue implementado en la definición de EMACScrip5 y puedes usar simplemente Object.create(). Pero vamos a ver que es lo que hace.

Object.create = function (o) {
    // Crea una funcion temporal
    function F() {
    }

    // Sobrescribe el prototype de la funcion F por 
    // el objeto que recibe como parametro por lo que 
    // F ahora hereda todas las propiedades de el objeto o
    F.prototype = o;
    
    // Por ultímo retornamos una instancia del objeto F(), esta 
    // instancia hereda los métodos y propiedades del objeto o pasado 
    // como parámetro, o podemos decir que es una copia de él.
    return new F();
};

Es importante que entendamos bien esto por lo que veamos un pequeño ejemplo.

var carros = {
    tipo: "sedan",
	ruedas: 4
};

var toyota = Object.create (carros);
//Como vemos el objeto toyota hereda todos los atributos del objeto carros.

console.log(toyota.tipo); // sedan

Muy bien ahora que entendemos esto podemos pasar al siguiente punto la Parasitic Combination Inheritance para eso debemos implementar una función que nos permitirá crear la herencia y que explicaremos a continuación.

function inheritPrototype(hijo, padre) {
    // como discutimos antes el método de Crockford nos permite copiar
    //   copia las propiedades y metodos de unobjeto en otro por lo que 
    //   copiaPadre es una copia de padre
    var copiaPadre = Object.create(padre.prototype);

    // entonces debemos apuntar el constructor de la copia al hijo ya que 
    // como vimos antes el constructor de la copia desaparece y debemos 
    // sobreescribirlo para asegurarnos que apunte a la función correcta.
    copiaPadre.constructor = hijo;

    // Finalmente sobrescribimos el prototype del hijo con la copia del padre
    // de esta forma el hijo hereda todas las propiedades del objeto padre 
    hijo.prototype = copiaPadre;
}


Es muy importante entender esta función anterior ya que en esta se basa todo el asunto de la herencia en ella lo que hacemos es que el hijo herede todas las propiedades y atributos del padre pero usando la copia como un intermediario.

Bien se que hasta ahora ha sido un poco confuso pero espero que me sigan, vamos a ver un ejemplo para poder ver todo esto funcionando en pleno.

Deciamos que haríamos un examen y los exámenes tienen preguntas por lo que crearemos preguntas de diferentes tipos. Primero creamos la función padre

var Pregunta = function ( laPregunta, lasOpciones, laRespuesta){
    this.pregunta =  laPregunta;
	this.opciones =  lasOpciones;
	this.respuesta =  laRespuesta;
	this.respuestaUsuario = "";
	// veamos como crear variables privadas que no puedes ser accedidas mediante la instancia
	var fecha = new Date();

	// Tambien podemos crear constantes disponibles para todas las instancias mediante metodos 
	// publicos que accedan a las variables privadas
	var FECHA_DE_CREACION = fecha.toLocaleDateString();

    // Debemos crear una método para acceder a la variable FECHA_DE_CREACION que sea 
    // publico, esta es una forma de definir privilegios de acceso a los atributos.
	this.getFechaCreacion = function () {
		return  FECHA_DE_CREACION;
	};
}; 

Ahora podremos modificar el Prototype del objeto padre para agregar algunos comportamientos a la clase como obtener la respuesta correcta y mostrar las opciones.

Pregunta.prototype.getRespuestaCorrecta = function() {
    return this.respuesta;
};

Pregunta.prototype.getRespuestadelUsuario = function() {
	return  this.respuestaUsuario;
};

Pregunta.prototype.mostrarOpciones = function() {
	var preguntaMostrar = "<div class='pregunta'>" + this.pregunta + "</div><ul>";
        contador = 0;
    this.opciones.forEach(function (opcion)  {
        preguntaMostrar += '<li><input type="radio" name="opcion" value="' + contador + '">' + opcion + '</li>';
        contador++;
    });
    preguntaMostrar += "</ul>";
    console.log (preguntaMostrar);
};


Ahora que tenemos lista la“Super clase” podemos dedicarnos a crear “Sub clases” a partir de ellas.

Preguntas con múltiples opciones

var SeleccionMultiple = function (laPregunta, lasOpciones, laRespuesta) {
    // Lo que haremos en esta parte sera hacer que la clase seleccion multiple llame al 
	// método constructor de la clase pregunta mediante call y pasaremos como parametro 
	// el mismo objeto SeleccionMultiple mediante this

	Pregunta.call(this, laPregunta, lasOpciones, laRespuesta);
};


Luego usaremos el método que definimos anteriormente para aplicar el patrón de Parasitic Combination Inheritance a nuestra aplicación.

inheritPrototype(SeleccionMultiple, Pregunta);


Después de esto todos los atributos y metidos del padre pasaran al hijo y podremos agregar nuevos métodos al hijo. Tienes que tener cuidado en este punto los métodos al hijo deben agregarse luego de hacer la herencia del padre sino serán sobrescritos al modificar el prototype.

Por último veamos algo muy necesario en la POO que es sobrescribir métodos, por que no todos los hijos hacen las cosas como sus padres.

Preguntas Drag and drop

var DragandDrop = function (laPregunta, lasOpciones, laRespuesta) {
    Pregunta.call(this, laPregunta, lasOpciones, laRespuesta);
}

inheritPrototype(DragandDrop, Pregunta);

Para modificar un metodo solo debemos modificar el prototype del objetoluego de la herencia.

DragandDrop.prototype.mostrarOpciones = function () {
    console.log(this.pregunta);
};


De esta forma las preguntas de selección múltiple mostrarán un div con la pregunta y radio buttons con las opciones en cambio las preguntas de Drag and Drop solo mostrarán un texto con la pregunta.

Hay muchas formas de realizar herencia incluso librerías que lo hacen mucho más sencillo pero lo importante es que entiendas los conceptos básicos de como funcionan estas librerías, además esta es una de las formas más optimizadas para realizar herencia en JavaScript.