Herencia en Node.js: Clases y Prototipos

Herencia en Node.js: Clases y Prototipos

¿En qué consiste la Herencia en la Programación Orientada a Objetos?

Si revisamos nuestro código podremos ver que tenemos un problema de conceptos en esta línea.

var eventos = require("events");
var control_remoto = new eventos();

Nuestro control remoto, hereda desde el modulo events (eventos), quizá para este sencillo ejercicio no represente gran problema, pero… ¿Todos nuestros elementos tienen que heredar directamente de la misma clase?

Vamos mas profundo en esto, si sabemos que nuestro control remoto representa una clase, y nuestro robot otra. ¿Por qué tenemos todo sobre el control remoto?. Diseñemos un poco entonces pensando en una mejor organización.

Todos los robots que vamos a crear saludan, van al frente y hacia atrás… Cuando la palabra todos va implícita, sabemos que el método forma parte de nuestra clase, y cuando es así se agrega a la clase mediante prototype.

// Todos los robots tienen un nombre
function Robot(nombre) {
    this.nombre = nombre;
}

// Todos los robots saludan
Robot.prototype.saludar = function () {
    console.log("Hola, mi nombre es " + this.nombre);
};

// Todos los robots caminan al frente
Robot.prototype.frente = function () {
    console.log(this.nombre + " camina hacia el frente");
};

// Todos los robots caminan hacia atras
Robot.prototype.atras = function () {
    console.log(this.nombre + " camina hacia atras");
};

// Crear un nuevo robot
var genialo = new Robot("Genialo");

// Ejecutar sus métodos
genialo.saludar();
genialo.frente();
genialo.atras();

Herencia y eventos

Pero resulta ser que genialo (el robot) tiene algunas particularidades cuando realiza alguna acciones, por ejemplo… Cuando a genialo se le indica caminar, da 2 pasos.

Primero empezamos importando los módulos util y events, y utilizamos util para expandir la clase Robot de manera que contenga los métodos de events.

// Modulo events
var events = require("events");

// Modulo util
var util = require("util");

// Todos los robots tienen un nombre
function Robot(nombre) {
    this.nombre = nombre;
}

// Heredar los métodos de eventos en Robot
util.inherits(Robot, events);

Después, a cada método de Robot le agregamos un emit.

// Todos los robots saludan
Robot.prototype.saludar = function () {
    console.log("Hola, mi nombre es " + this.nombre);
    this.emit("saludar");
};

// Todos los robots caminan al frente
Robot.prototype.frente = function () {
    console.log(this.nombre + " camina hacia el frente");
    this.emit("frente");
};

// Todos los robots caminan hacia atras
Robot.prototype.atras = function () {
    console.log(this.nombre + " camina hacia atras");
    this.emit("atras");
};

Finalmente a Genialo le agregamos las funciones que se dispararán cuando estos eventos sucedan.

var genialo = new Robot("Genialo");

// cuando genialo va al frente, dar dos pasos al frente
genialo.on("frente", function () {
    console.log(this.nombre + " da dos pasos al frente");
});

// cuando genialo va atras, dar dos pasos atras
genialo.on("atras", function () {
    console.log(this.nombre + " da dos pasos atras");
});

genialo.saludar();
genialo.frente();
genialo.atras();

Métodos de la clase vs evento

  1. Cuando un comportamiento existe en todos las instancias (objetos) de una clase, agregamos el método a la clase mediante el prototype.
  2. Cuando el comportamiento es una particularidad de una instancia (objeto), agregamos una o varias funciones al evento relacionado.

Herencia y propiedades

¿Cómo heredar las propiedades de otra clase en JavaScript?

Si deseamos que una clase herede las propiedades de otra, su constructor tiene que utilizar la función call.

function Clase1() {
    this.prop1 = "a";
    this.prop2 = "b";
}

function Clase2() {
    Clase1.call(this);
    this.prop3 = "c";
}

var c1 = new Clase1();
var c2 = new Clase2();

console.log(c1);
console.log(c2);

Aquí Clase2 hereda todas las propiedades de Clase1 y añade una propiedad adicional prop3.

El resultado sería el siguiente.

Clase1 { prop1: 'a', prop2: 'b' }
Clase2 { prop1: 'a', prop2: 'b', prop3: 'c' }