DMarlon Studio

Lección 6 · 6 de 20

Miembros estáticos y Symbol · JavaScript

Use static en JavaScript para contadores y métodos factoría de clase, y Symbol para claves únicas y para cambiar cómo se convierte un objeto.

JavaScript · Miembros estáticos y Symbol en DMarlon Studio: el código del ejemplo y su salida en la terminal

Lo marcado con `static` pertenece a la clase, no a cada objeto. Order.TAX es una constante común a todos los pedidos y static #nextId es un contador privado de la clase: cada new Order lo lee y lo incrementa con Order.#nextId++, así que los pedidos reciben 1, 2 y 3 sin repetirse.

Un método estático se llama sobre la clase: Order.fromLine("Ana;100"). Es un patrón muy común, la factoría: convierte una línea de texto (de un CSV, por ejemplo) en un pedido, separando el cliente y el importe con split.

Un `Symbol` es un valor único que sirve como clave de propiedad. JavaScript define algunos símbolos conocidos que cambian el comportamiento del lenguaje: Symbol.toPrimitive decide en qué se convierte el objeto (en texto dentro de una plantilla, o en el importe con IVA en Number(o), que la suma usa para el total) y Symbol.toStringTag cambia lo que muestra Object.prototype.toString: [object Order].

También puede crear sus propios símbolos: orders[2][internal] guarda un dato que no aparece en Object.keys ni choca con ninguna otra propiedad, porque cada símbolo es distinto (Symbol("id") === Symbol("id") es false). Symbol.for("id"), en cambio, usa un registro global y devuelve siempre el mismo.

Código · main.js

class Order {  static #nextId = 1; // belongs to the class, shared by all orders  static TAX = 0.21;  static fromLine(line) { // static factory: Order.fromLine("Ana;100")    const [customer, amount] = line.split(";");    return new Order(customer, Number(amount));  }  constructor(customer, amount) {    this.id = Order.#nextId++;    this.customer = customer;    this.amount = amount;  }  // Well-known symbols change how the language treats the object.  get [Symbol.toStringTag]() {    return "Order";  }  [Symbol.toPrimitive](hint) {    if (hint === "number") return this.amount * (1 + Order.TAX);    return `Order #${this.id} for ${this.customer}`;  }}const orders = ["Ana;100", "Luis;40", "Marta;250"].map((line) => Order.fromLine(line));console.log(`${orders[0]} | ${orders[2]}`);console.log("Total with tax:", orders.reduce((sum, o) => sum + Number(o), 0).toFixed(2));console.log(Object.prototype.toString.call(orders[1]), "| TAX:", Order.TAX);// A Symbol is a unique key: it never clashes with other properties.const internal = Symbol("internal");orders[2][internal] = "priority";console.log("Keys:", Object.keys(orders[2]).join(", "));console.log("Symbol value:", orders[2][internal]);console.log("Unique:", Symbol("id") === Symbol("id"), "| registry:", Symbol.for("id") === Symbol.for("id"));

Salida · node main.js

Order #1 for Ana | Order #3 for Marta
Total with tax: 471.90
[object Order] | TAX: 0.21
Keys: id, customer, amount
Symbol value: priority
Unique: false | registry: true

Para recordar

  • Los miembros static pertenecen a la clase y se usan como Clase.miembro.
  • Un método estático factoría crea objetos a partir de otros datos.
  • Cada Symbol() es único y sirve como clave que no choca con otras.
  • Symbol.toPrimitive y Symbol.toStringTag cambian cómo se convierte y se muestra un objeto.

Ejercicio

Añada a Order un método estático count() que devuelva cuántos pedidos se han creado (a partir de #nextId) y use un símbolo propio, Symbol("notes"), para guardar una nota en el pedido de Luis.