Saltar al contenido principal

Campos de clase públicos y privados

· 5 min de lectura
Mathias Bynens ([@mathias](https://twitter.com/mathias))

Varias propuestas amplían la sintaxis existente de clases en JavaScript con nuevas funcionalidades. Este artículo explica la nueva sintaxis de campos de clase públicos en V8 v7.2 y Chrome 72, así como la próxima sintaxis de campos de clase privados.

Aquí hay un ejemplo de código que crea una instancia de una clase llamada IncreasingCounter:

const counter = new IncreasingCounter();
counter.value;
// registros '¡Obteniendo el valor actual!'
// → 0
counter.increment();
counter.value;
// registros '¡Obteniendo el valor actual!'
// → 1

Nota que acceder a value ejecuta algún código (es decir, registra un mensaje) antes de devolver el resultado. Ahora pregúntate, ¿cómo implementarías esta clase en JavaScript? 🤔

Sintaxis de clases de ES2015

Aquí se muestra cómo IncreasingCounter podría implementarse utilizando la sintaxis de clases de ES2015:

class IncreasingCounter {
constructor() {
this._count = 0;
}
get value() {
console.log('¡Obteniendo el valor actual!');
return this._count;
}
increment() {
this._count++;
}
}

La clase instala el getter value y un método increment en el prototipo. Más interesante aún, la clase tiene un constructor que crea una propiedad de instancia _count y establece su valor predeterminado en 0. Actualmente, tendemos a usar el prefijo de guion bajo para denotar que _count no debería ser utilizado directamente por los consumidores de la clase, pero eso es solo una convención; no es realmente una propiedad "privada" con semántica especial aplicada por el lenguaje.

const counter = new IncreasingCounter();
counter.value;
// registros '¡Obteniendo el valor actual!'
// → 0

// Nada impide que las personas lean o interfieran con la
// propiedad de instancia `_count`. 😢
counter._count;
// → 0
counter._count = 42;
counter.value;
// registros '¡Obteniendo el valor actual!'
// → 42

Campos de clase públicos

La nueva sintaxis de campos de clase públicos nos permite simplificar la definición de la clase:

class IncreasingCounter {
_count = 0;
get value() {
console.log('¡Obteniendo el valor actual!');
return this._count;
}
increment() {
this._count++;
}
}

La propiedad _count ahora está declarada de manera ordenada en la parte superior de la clase. Ya no necesitamos un constructor solo para definir algunos campos. ¡Genial!

Sin embargo, el campo _count sigue siendo una propiedad pública. En este ejemplo particular, queremos evitar que las personas accedan directamente a la propiedad.

Campos de clase privados

Es aquí donde entran en juego los campos de clase privados. La nueva sintaxis de campos privados es similar a los campos públicos, excepto que marcas el campo como privado usando #. Puedes pensar en el # como parte del nombre del campo:

class IncreasingCounter {
#count = 0;
get value() {
console.log('¡Obteniendo el valor actual!');
return this.#count;
}
increment() {
this.#count++;
}
}

Los campos privados no son accesibles fuera del cuerpo de la clase:

const counter = new IncreasingCounter();
counter.#count;
// → SyntaxError
counter.#count = 42;
// → SyntaxError

Propiedades estáticas públicas y privadas

La sintaxis de campos de clase puede usarse para crear propiedades y métodos estáticos públicos y privados también:

class FakeMath {
// `PI` es una propiedad estática pública.
static PI = 22 / 7; // Lo suficientemente cerca.

// `#totallyRandomNumber` es una propiedad estática privada.
static #totallyRandomNumber = 4;

// `#computeRandomNumber` es un método estático privado.
static #computeRandomNumber() {
return FakeMath.#totallyRandomNumber;
}

// `random` es un método estático público (sintaxis ES2015)
// que utiliza `#computeRandomNumber`.
static random() {
console.log('He oído que te gustan los números aleatorios…');
return FakeMath.#computeRandomNumber();
}
}

FakeMath.PI;
// → 3.142857142857143
FakeMath.random();
// registros 'He oído que te gustan los números aleatorios…'
// → 4
FakeMath.#totallyRandomNumber;
// → SyntaxError
FakeMath.#computeRandomNumber();
// → SyntaxError

Subclasificación más sencilla

Los beneficios de la sintaxis de campos de clase se vuelven aún más claros al trabajar con subclases que introducen campos adicionales. Imagina la siguiente clase base Animal:

class Animal {
constructor(name) {
this.name = name;
}
}

Para crear una subclase Cat que introduzca una propiedad de instancia adicional, anteriormente tendrías que llamar a super() para ejecutar el constructor de la clase base Animal antes de crear la propiedad:

class Cat extends Animal {
constructor(name) {
super(name);
this.likesBaths = false;
}
meow() {
console.log('¡Miau!');
}
}

Es mucha preparación solo para indicar que los gatos no disfrutan los baños. Afortunadamente, la sintaxis de campos de clase elimina la necesidad de todo el constructor, incluida la llamada incómoda a super():

class Cat extends Animal {
likesBaths = false;
meow() {
console.log('¡Miau!');
}
}

Soporte de características

Soporte para campos de clase públicos

Soporte para campos de clase privados

Soporte para métodos privados y accesorios