Herencia de Clases

A medida que trabajamos con Clases y objetos en nuestro código, una de las características fundamentales que nos ayudan a reutilizar código y simplificar nuestro trabajo es la herencia de Clases. Con esta característica podemos establecer una jerarquía de elementos y reutilizar características según en que nivel se encuentra cada elemento.

Tomemos el ejemplo del capítulo anterior de la forma geométrica para trabajar con él:

Herencia

Observa que en primer lugar tenemos una clase superior llamada Forma que representa a una forma geométrica. Dicha forma geométrica tendrá las características comunes a todos los elementos (color, nombre...).

Luego, vemos que tenemos varias clases: Cuadrado, Circulo y Triangulo. Dichas clases tendrán las características propias de cada una: el Cuadrado tendrá una característica que será lado, el Círculo tendrá radio y diametro, etc... Además, las clases heredan las características comunes de su padre, en este caso de la clase Forma.

Así, finalmente los elementos c1 y c2 son objetos generados a partir de la clase Cuadrado, los elementos r1 y r2 son objetos generados a partir de la clase Circulo y así sucesivamente.

¿Qué es extender una clase?

En Javascript, a partir de ECMAScript podemos «extender clases» de forma muy similar a como se hace en otros lenguajes de programación como Java. Veamos el ejemplo del capítulo anterior pasado a Clases que utilizan herencia:

// Clase padre
class Forma {
  constructor() {
    console.log("Soy una forma geométrica.");
  }

  gritar() {
    console.log("YEP!!");
  }
}

// Clases hijas
class Cuadrado extends Forma {
  constructor() {
    super();
    console.log("Soy un cuadrado.");
  }
}

class Circulo extends Forma {
  constructor() {
    super();
    console.log("Soy un círculo.");
  }
}

class Triangulo extends Forma {
  constructor() {
    super();
    console.log("Soy un triángulo.");
  }
}

Observa que la clase padre Forma muestra un mensaje en su constructor y tiene un método gritar(). Cada clase hija extiende a su clase padre, por lo que la clase Cuadrado será una mezcla de la clase Forma más la clase Cuadrado.

El método especial super() llama al constructor de la clase padre, por lo que si creamos varios objetos, funcionará en cascada, mostrando primero el texto del constructor del padre, y luego el texto del constructor del hijo:

const c1 = new Cuadrado();
// 'Soy una forma geométrica.'
// 'Soy un cuadrado.'

c1.gritar();
// 'YEP!!'

const t1 = new Triangulo();
// 'Soy una forma geométrica.'
// 'Soy un triángulo.'

t1.gritar();
// 'YEP!!'

Además, todas las clases hijas heredarán el método gritar(), ya que pertenece a la clase padre Forma y todas extienden de ella.

Recuerda que es obligatorio llamar a super() en el constructor de la clase hija antes de realizar ninguna tarea. No te olvides de escribirlo.

La palabra clave super

Como hemos visto, la palabra clave super() hace referencia a la superclase, es decir, a la clase padre. Se debe indicar de forma obligatoria en el constructor de las clases hijas que extienden de un padre, no obstante, también podemos utilizarlas en métodos para llamar de forma opcional u obligatoria a métodos del padre para que hagan tareas complementarias o parciales:

class Padre {
  tarea() {
    console.log("Tarea del padre...");
  }
}

class Hijo extends Padre {
  tarea() {
    super.tarea();
    console.log("Tarea del hijo...");
  }
}

Si nos fijamos en el ejemplo anterior, en el caso de que la clase Hijo no tuviera método tarea() heredaría dicho método de su clase padre, ejecutándolo. En el caso del ejemplo anterior, tiene un método tarea() en la clase hijo que sobreescribe el método tarea() del padre, realizando únicamente el código indicado en esa clase hija. Sin embargo, la diferencia radica en lo siguiente:

  • Si se indica super.tarea() (donde tarea es el nombre del método de la clase padre), esto llamará y ejecutará el método de la clase Padre, y al terminar, continua realizando el código del método de la clase hija. Es el caso del ejemplo anterior.

  • Si no se indica super.tarea(), el método tarea() de la clase hijo sobreescribe al de la clase Padre, ocultándolo y ejecutando sólo el código de la clase hija.

Es nuestra decisión que camino tomar, en algunos casos nos interesará una de estas posibilidades y en otras ocasiones nos interesará otra.

Manz
Publicado por Manz

Docente, divulgador informático y freelance. Autor de Emezeta.com, es profesor en la Universidad de La Laguna y dirige el curso de Programación web FullStack y Diseño web FrontEnd de EOI en Tenerife (Canarias). En sus ratos libres, busca GIF de gatos en Internet.