Clases en ES6

  • Por
Qué son las clases y cómo se declaran en Javascript con la especificación ECMAScript 2015 (ES6).

En Javascript no existía una manera específica de crear clases, de programación orientada a objetos (POO). Sí que existían diversas alternativas que se podrían usar para crear componentes parecidos a lo que serían las clases en la POO tradicional, pero lo cierto es que no existía una declaración "class" como se podría esperar.

Así que en la versión reciente de Javascript ES6 una de las novedades más importantes fue la incorporación de la declaración de clases. Aunque las clases en Javascript siguen sin ser exactamente lo que puedas conocer en lenguajes más tradicionales como Java, sí resulta un avance determinante. Es importante que lo conozcas, ya que ha sido muy bien acogido por la comunidad y las mejores librerías y frameworks se han decidido a incorporar las declaraciones de clases como mecanismo de creación de sus diferentes componentes o artefactos.

En este artículo no pretendemos explicar el concepto de clase, algo que ya hemos tratado en diversas ocasiones anteriores, como en el Manual de Programación Orientada a Objetos, sino que nos queremos centrar más en la sintaxis y alternativas para definir clases en Javascript con ES6.

Declaración de una clase en Javascript ECMAScript 2015

En ECMAScript 2015 (ES6) las clases se declaran de manera similar a otros lenguajes, usando la palabra "class", seguida del nombre de la clase que estamos creando.

class Coordenada {

}
Nota: Los nombres de las clases, igual que las variables o el lenguaje Javascript en general, son sensibles a mayúsculas y minúsculas. Podríamos llamarla como se desee, pero por convención se usa siempre la primera letra en mayúsculas.

Dentro de las llaves del "class" colocaremos el código de la clase. En lenguajes tradicionales serían típicamente los atributos y los métodos, pero en Javascript los atributos de instancia los tendremos que crear dentro del constructor.

Nota: Otra posibilidad de declarar atributos en objetos es usar los getters de Javascript (ya disponibles en ES5), que permiten definir una especie de propiedad computada, cuyo valor se establece con la ejecución de un método. Si te interesa saber algo más te recomendamos un artículo donde puedes aprender más sobre los setters y getters de Javascript.
class Coordenada {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
}

Esta clase define un constructor, que se encarga de resumir las tareas de inicialización de los objetos. En la inicialización creamos los atributos que debe contener todo objeto que se cree a partir de esta clase.

Nota: No puede haber más de un método llamado constructor en una clase de Javascript. Si por despiste colocamos más de uno recibiremos un mensaje de error "A class may only have one constructor". Esto indica que no es posible sobrecargar los constructores con las herramientas que te ofrece la creación de clases, aunque sí es posible hacerlo en la práctica, porque con Javascript puedes llamar a una misma función con distintos juegos de parámetros sin producir un error. El problema es que tendrías que implementar tú mismo mediante código la sobrecarga, recibiendo parámetros de manera predeterminada, examinando sus tipos, etc.

Instanciación de objetos a partir de una clase

Como en otros lenguajes, usamos la palabra "new" para crear nuevos objetos de una clase, seguida del nombre de la clase y todos los parámetros que se deban indicar para invocar al constructor.

var testCoordenada = new Coordenada(8,55);

El proceso de instanciación creará el nuevo objeto y su inicialización quedará en manos del constructor. En nuestro caso el construtor había creado dos propiedades para cada instancia, a los que les asignaba los valores de los puntos de la coordenada.

Los objetos poseen propiedades, también llamados atributos, que se hayan definido en el momento de creación de la clase o en cualquier otro momento de la vida de ese objeto. En nuestro caso se crearon los atributos "x" e "y".

Nota: La palabra "this" dentro del constructor, o cualquier otro método de la clase, hace referencia al objeto que ha recibido ese método. Si es el constructor hace referencia al objeto que se está creando. Si es en un método hace referencia al objeto que recibió el mensaje (invocación del método).

Una vez creados los objetos podríamos acceder a sus atributos a partir del operador punto ("."). Usamos el nombre del objeto que acabamos de crear, el operador punto y el nombre del atributo al que queramos acceder.

console.log(testCoordenada.x);

Eso nos imprimiría en la consola el valor del atributo "x" del objeto que se había creado anteriormente.

Creación de métodos en la clase

Las clases en ES6 pueden declarar sus métodos de una manera resumida, pues nos ahorramos la palabra "function" en la declaración de la función.

Nota: Un método es una función asociada a un objeto. Por ejemplo, la clase "puerta" puede tener el método "abrir" y entonces todos los objetos puerta podrán recibir el mensaje "abrir", provocando la apertura de la puerta. Los métodos los puedes entender como funciones, solo que se ejecutan en el contexto de un objeto que haya sido creado.

En el código del ejemplo de la coordenada ya teníamos un método, aunque algo especial, ya que era el método constructor. El constructor debe tener siempre el nombre "constructor", pero podríamos crear otros métodos con cualquier otro nombre.

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

  esIgual(coordenada) {
    if (this.x == coordenada.x && this.y == coordenada.y) {
      return true;
    }
    return false;
  }
}

En el código anterior hemos agregado el método "esIgual" que se encarga de decir si una coordenada recibida por parámetro tiene los mismos valores de x e y que la coordenada que ha recibido el mensaje.

Nota: La definición de métodos sin la palabra "function" es una de las novedades interesantes en ES6, azúcar sintáctico, disponible también a la hora de crear objetos a partir de literales.

Recuerda que los métodos se invocan sobre el nombre del objeto, con el operador punto y el nombre del método, seguido por sus parámetros. Podríamos usar esta clase y el nuevo método con este código:

var testCoordenada = new Coordenada(8,55);
console.log(testCoordenada.esIgual(new Coordenada(3, 1)))

Al ejecutar esto, veríamos "false" en la consola de Javascript.

Declaraciones de clases siempre antes de su uso

Es indispensable que se declaren las clases antes de usarlas. A diferencia de las funciones en Javascript, que se pueden usar antes de haber sido declaradas, las clases deben conocerse antes de poder instanciar objetos.

Es decir, un código como este no funcionaría:

var x = new MiClase();
class MiClase {}:

Si intentas ejecutarlo, recibirías por consola un mensaje como este: "Uncaught ReferenceError: MiClase is not defined".

Expresiones de clases ES6

Otra manera de declarar clases en ES6 es mediante lo que se conoce como expresiones. Básicamente consiste en crear una variable y asignarle una expresión definida mediante class y las llaves.

var Persona = class {
  constructor(nombre) {
    this.nombre = nombre;
  }
}

La clase puede ser anónima, como en el ejemplo anterior, aunque también podría tener un nombre.

Nota: Esto es igual que las funciones, que puedes asignarle una función a una variable y es similar a haber declarado la función como se hace tradicionalmente. Y digo similar, porque al apoyarte en una variable en realidad sí hay diferencias, pues el ámbito de la variable que estás definiendo (var Persona) puede ser diferente al ámbito de la clase si la hubieras declarado de manera tradicional, debido al hoisting de Javascript. A mi juicio no aporta mucho este modo de declaración de clases y no lo he visto usar en ninguna documentación.

El uso de una clase definida con una expresión, a la hora de instanciar objetos, es exactamente el mismo que hemos visto anteriormente.

var miguel = new Persona('Miguel Angel Alvarez');
console.log(miguel.nombre);

Ahora ya sabes declarar clases en ES6, así como definir métodos. Has aprendido a usarlas para instanciar objetos y luego a usar esos objetos para el acceso a sus miembros, tanto sus atributos como sus métodos.

En siguientes artículos exploraremos más características de ECMAScript 2015 relacionadas con las clases.