Cosas Digitales pone a tu disposición una completa guía práctica de Programación Orientada a Objetos en Javascript para comprender este paradigma en su totalidad, analizándola desde su base y ofreciéndote en cada entrega lotes de ejemplos prácticos en descarga directa.
Descargar lote de ejemplos II – Clases en Javascript
Las clases de Javascript permiten manejar el prototipado y herencia del lenguaje de una forma sintácticamente clara, simplificada y con cierta semejanza frente a cómo otras tecnologías manejan POO. Basándonos en los ejemplos publicados en la entrada sobre objetos literales en Javascript (pásate antes por allí), ¿qué sucede cuando necesitamos no una factura, sino una fábrica de facturas?
No es necesario declarar un objeto literal por factura: las clases permiten crear cómodamente objetos (instancias) que comparten la misma estructura pero dotan a cada instancia de su información particular.
Declarar una clase en Javascript
A diferencia de las funciones constructoras, las clases deben ser declaradas previo a ser instanciadas, es decir, por encima de aquellas instrucciones que hagan uso de estas clases para crear instancias.
Podemos crear una clase que contenga la estructura y características del objeto mediante la palabra reservada class:
class Factura { /* --- métodos y propiedades del objeto --- */ }
En su interior formularemos los métodos necesarios, eligiendo entre los cuatro tipos de métodos que nos ofrece Javascript.
Método constructor
Cada clase puede tener, opcionalmente, un método constructor. Este es único (sólo puede haber uno por clase) y la facilidad que aporta en la futura inicialización de cada instancia lo hace casi imprescindible en una clase.
Mediante el método constructor declaramos los nombres de las propiedades que compartirán todas las instancias – precedidas por la palabra clave this – asignándoles a través de los parámetros los valores específicos de cada instancia:
class Factura { constructor(numero, cliente, divisa, subtotal, IVA) { this.numero = numero; this.cliente = cliente; this.divisa = divisa; this.subtotal = subtotal; this.IVA = IVA; } }
Es posible ya inicializar una instancia de Factura mediante la palabra clave new, transfiriendo los valores para cada propiedad en forma de argumentos:
const factura1 = new Factura(201, "Transportes SA", "eur", 542, 113); const factura2 = new Factura(202, "Mudanzas SA", "eur", 100, 21); console.log("La factura " + factura1.numero + " está en divisa " + factura1.divisa); // La factura 201 está en divisa eur
Propiedades de la clase
Podemos crear propiedades personalizadas que no se ajusten a ninguna de las presentes en el método constructor mediante las palabras clave get y set.
Gracias a su formato de función, podemos dotar al objeto de propiedades que sean resultado de operaciones internas, a diferencia de los objetos literales y de las funciones constructoras, donde las funciones son incompatibles como valor de propiedades.
Aquí un ejemplo de método get:
class Factura { /* ... */ get total() { return this.subtotal + this.IVA; } } const factura = new Factura(201, "Transportes SA", "eur", 100, 21); console.log("La factura " + factura.numero + " tiene un total de " + factura.total + " " + factura.divisa); // La factura 201 tiene un total de 121 eur
También podemos usar métodos set, que permiten transferir valores específicos a una propiedad:
class Factura { /* ... */ get total() { return this.subtotal + this.IVA; } set nuevaDivisa(valor) { this.divisa = valor; } } let factura = new Factura(201, "Transportes SA", "eur", 100, 21); console.log("La factura " + factura.numero + " tiene un total de " + factura.total + " " + factura.divisa); // La factura 201 tiene un total de 121 eur factura.nuevaDivisa = "GBP"; console.log("La factura " + factura.numero + " tiene un total de " + factura.total + " " + factura.divisa); // La factura 201 tiene un total de 121 GBP
Métodos prototipo de la clase
La morfología de los métodos prototipo tiene una amplia similitud con la utilizada en los métodos de los objetos literales:
class Factura { /* ... */ aplicarDescuento(porcentaje) { this.subtotal -= this.subtotal / 100 * porcentaje; } } const factura = new Factura(201, "Transportes SA", "eur", 100, 21); factura.aplicarDescuento(50); console.log("La factura " + factura.numero + " tiene ahora un total de " + factura.total + " " + factura.divisa); // La factura 201 tiene un total de 71 eur
Métodos estáticos de la clase
Los métodos estáticos pueden ser accedidos sin necesidad de ser instanciados:
class Factura { /* ... */ static instrucciones(){ console.log("Indica para cada factura su numero, cliente, divisa, subtotal e IVA en este orden"); } } Factura.instrucciones(); // Indica para cada factura su numero, cliente, divisa, subtotal e IVA en este orden
Aunque en realidad, estos métodos suelen utilizarse para implementar funciones que pertenecen al objeto, no a ninguna instancia en particular:
class Factura { /* ... */ static calcularDiferencia(factura1, factura2){ return factura1.total - factura2.total; } } const factura1 = new Factura(201, "Transportes SA", "eur", 542, 113); const factura2 = new Factura(202, "Mudanzas SA", "eur", 100, 21); console.log("La diferencia entre las facturas es de " + Factura.calcularDiferencia(factura1, factura2) + " eur"); // La diferencia entre las facturas es de 534 eur
Conclusión
Las clases en Javascript no suponen la introducción de nuevos modelos en el lenguaje sino que ofrecen un enfoque más tradicional y simple en su declaración, acercando su sintaxis y concepción de POO a otras tecnologías con similares capacidades.
Facilita sensiblemente la herencia, abstracción y encapsulación (que veremos en futuras entradas) mediante un código eficiente que, ahora si, resuelve los entresijos de este paradigma de la forma que hace tiempo se venía reclamando.
Puedes descargarte todos los ejemplos de esta entrada mediante este enlace:
Descargar lote de ejemplos II – Clases en Javascript
¿Dudas? Abajo, en los comentarios.