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.