> Manuales > Manual de ES6

Explicamos los mecanismos y la sintaxis de herencia en las clases de Javascript, disponibles a partir de ES6 (ECMAScript 2015).

En el artículo anterior conocimos las clases en ES6 con detalle, creación de clases, métodos, constructores, etc. No obstante, nos quedan cosas por aprender y ahora nos vamos a dedicar a conocer la herencia de la Programación Orientada a Objetos. Estudiaremos brevemente lo que consiste la herencia, pero sobretodo nos centraremos en la manera de implementarla en el lenguaje Javascript a partir de la especificación ECMAScript, edición de 2015.

A nivel conceptual, la herencia es un mecanismo por el cual unas clases pueden ser construidas en base a otras. Las clases originales, que nos sirven de base, podemos llamarlas padres y a las clases que se construyen en base a los padres podemos llamarlas hijos. Ante la herencia, las clases padre transmiten sus miembros (atributos y métodos) a las clases hijo. También se dice que la clase hija deriva de la clase padre.

Nota: No vamos a agregar mucho más de teoría, pues entendemos que el lector la conoce. Si no es así, recomendamos la lectura del artículo sobre Herencia en la Programación Orientada a Objetos.

Extender clases en ES6

Extender una clase es el mecanismo por el cual una clase se construye en base a otra, es decir, el mecanismo mediante el cual se construyen clases hijas o clases derivadas. Obviamente, para extender, lo primero que debemos tener es la clase padre y mediante esta extensión construir una clase hija.

En Javascript, igual que en muchos otros lenguajes, para extender una clase en base a otra usamos la palabra "extends".

class Coordenada3D extends Coordenada {

}

En este caso, la clase Coordenada3D es la clase hija y la clase Coordenada es la clase padre. Por tanto, la clase Coordenada3D hereda todas las propiedades y métodos existentes en la clase Coordenada.

Nota: Tienes el código de la clase Coordenada en el artículo anterior sobre las clases en ES6.

En el caso particular de las clases de Javascript vimos que las propiedades se crean en tiempo de ejecución, es decir, no se declaran, por lo que en realidad lo que estamos heredando son únicamente los métodos.

Invocación al constructor de la clase padre

Es algo habitual que la clases hijas se apoyen en los constructores de las clases padre para poder hacer sus tareas de inicialización y creación de las propiedades o atributos de la clase. Para ello es posible invocar al método constructor de la clase padre, dentro del código del constructor de la clase hija.

El mecanismo para invocar a métodos existentes en la implementación del padre es mediante la palabra "super" y los paréntesis de invocación de métodos.

class Coordenada3D extends Coordenada {
  constructor(x, y, z) {
    super(x, y);
    this.z = z;
  }
}

Una coordenada de 3 dimensiones se define mediante tres puntos (x, y, z). Así pues, el constructor de la Coordenada3D debe inicializar esos tres puntos. La clase Coordenada original (clase padre) ya inicializaba dos de ellos, por lo que no necesitamos repetir el código que había en Coordenada para esas inicializaciones. En el código anterior podemos apreciar cómo para la inicialización de los atributos "x" e "y" se invoca al constructor de la clase padre, mediante super(x, y). Ya solo nos quedaría inicializar el tercer atributo "z".

Nota: Al extender una clase tiene todo el sentido apoyarse en el código de la clase hija. En este caso en concreto no se ahorra demasiado código, pero en clases mayores sin duda el ahorro de código es mucho mayor. Además, en la mayoría de los casos el beneficio no es solamente evitar repetir unas pocas líneas de código, sino evitar mantener el mismo código en dos lugares distintos.

Obligación de invocar a super() en el constructor de las clases derivadas

Hasta aquí todo te sonará de otros lenguajes, si es que ya tienes nociones de programación orientada a objetos. Sin embargo en Javascript hay un detalle importante que llama la atención en el caso de los constructores de clases derivadas. Básicamente resulta que, si quieres usar "this" en el constructor de la clase hija, estás obligado a llamar a super() previamente.

Es decir, como en la práctica siempre vas a querer usar this para referirte al objeto que se está construyendo, necesitarás invocar a super() siempre con antelación, para que el constructor de la clase padre haga su trabajo, antes de comenzar a operar con el objeto que se está construyendo en el contexto de la clase hija.

Por ejemplo, el siguiente código produciría un error: "Uncaught ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor"

class Coordenada3D extends Coordenada {
  constructor(x, y, z) {
    this.x = x;
    this.y = y;
    this.z = z;
  }
}

Tampoco podrás hacer esto:

class Coordenada3D extends Coordenada {
  constructor(x, y, z) {
    this.z = z;
    super(x, y);
  }
}

Sobreescritura de métodos

La redefinición o sobreescritura de métodos es una de las tareas habituales al extender clases. Consiste en reprogramar ciertas operaciones en la clase hija, algo que se traduce en la reescritura del código de los métodos que teníamos en el padre. Para conseguirlo simplemente se tiene que volver a declarar el método con el mismo nombre existente en la clase padre.

La reescritura del constructor, explicada en el paso anterior, es un caso particular de la redefinición de métodos. En general, no solamente tendremos que programar un nuevo constructor. Realmente, al extender la clase hija es habitual que tengamos que redefinir métodos existentes en la clase padre.

Como en el caso del constructor, podemos invocar al método original, tal como se había implementado en la clase padre, mediante super().

class Coordenada3D extends Coordenada {
  constructor(x, y, z) {
    super(x, y);
    this.z = z;
  }

  esIgual(coordenada3D) {
    if(super.esIgual(coordenada3D) && this.z == coordenada3D.z) {
      return true;
    }
    return false;
  }
}

En este caso hemos realizado la redefinición del método esIgual(), en la que se tiene que controlar si la coordenada tiene iguales los tres puntos. Dos de ellos se verifican invocando al método de la clase padre y el otro es tarea de la clase hijo.

Miguel Angel Alvarez

Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...

Manual