HOWTO · JavaScript
Variables estáticas en JavaScript
Este tutorial presenta variables estáticas en JavaScript.
En esta página
JavaScript permite conservar un valor entre llamadas mediante un campo estático público de una clase, una propiedad de un objeto función o una variable local que permanece activa gracias a un cierre. Estos patrones conservan el estado, pero difieren en dónde se encuentra y quién puede acceder a él. Usa un campo de clase para el estado compartido por una clase, una propiedad de función para un estado público sencillo asociado a una función, o un cierre cuando quieras que el código que llama use el valor sin leer ni modificar directamente su vínculo.
Qué significa una variable estática en JavaScript
Una variable estática es un estado asociado a una función o clase, y no a una llamada concreta. JavaScript no ofrece una única declaración de variable estática válida para todas las funciones; en su lugar, ofrece varios patrones. La palabra clave static declara un campo o método de clase que pertenece a la propia clase. Una propiedad asignada a una función también pertenece al objeto función. Un cierre mantiene un vínculo local disponible para una función interna después de que la función externa haya terminado.
Estos conceptos están relacionados, pero sus mecanismos no son intercambiables en todos los aspectos. Los campos de clase y las propiedades de función se pueden consultar a través del objeto de función o de clase al que pertenecen. Un cierre puede mantener privado su vínculo y exponer solo las operaciones que elijas.
Usa un campo estático de clase para compartir estado entre instancias
Un campo estático público de una clase pertenece a la clase, por lo que todas las instancias acceden al mismo campo a través del nombre de la clase. El campo no se copia en cada instancia. Esta sintaxis requiere un entorno de ejecución que admita campos estáticos públicos de clase. Si tu entorno no los admite, usa el patrón de propiedad de función o el de cierre que se explican más abajo.
Ejecuta este ejemplo:
El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.
class VisitCounter {
static count = 0;
static recordVisit() {
return ++VisitCounter.count;
}
}
console.log(VisitCounter.recordVisit());
console.log(VisitCounter.recordVisit());
console.log(VisitCounter.count);
1
2
2
Ambas llamadas actualizan el mismo VisitCounter.count. Como el campo es público, el código también puede leerlo o asignarle un valor mediante VisitCounter.count; si la propia clase debe controlar el acceso, usa un campo estático privado (con un nombre que empiece por #). Los miembros estáticos se consultan en la clase, no en una instancia como new VisitCounter().
Asigna una propiedad a una función
Las funciones son objetos, así que una función con nombre puede tener una propiedad cuyo valor persiste entre llamadas. Es una opción compacta para un contador o una caché vinculados a una función. La propiedad es pública: otro código puede consultar o cambiar nextId.counter, por lo que este patrón no ofrece privacidad.
El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.
function nextId() {
nextId.counter = (nextId.counter ?? 0) + 1;
return nextId.counter;
}
console.log(nextId());
console.log(nextId());
console.log(nextId.counter);
1
2
2
La misma idea se aplica a una función constructora. Una propiedad como Widget.count pertenece a la función constructora, mientras que widget.name pertenece a una instancia concreta. Cada instancia no recibe su propia copia de Widget.count; el código accede a esa propiedad compartida mediante Widget. En cuanto a dónde se almacena el estado, esto se parece al estado compartido por una clase, pero las propiedades de función de JavaScript no ofrecen todos los controles de acceso ni las garantías de tipos de algunos sistemas de clases.
Usa un cierre para mantener privado el estado
Un cierre permite que una función interna siga usando un vínculo local después de que termine la función externa. Una IIFE (expresión de función invocada inmediatamente) crea ese ámbito externo en el momento y devuelve una operación que puede actualizar el valor conservado. Como el vínculo no se coloca en un objeto público, el código externo no puede leerlo ni asignarle directamente un valor.
El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.
const counter = (function () {
let count = 0;
return function () {
return ++count;
};
})();
console.log(counter());
console.log(counter());
1
2
Aquí, counter conserva acceso a count mediante un cierre; cada llamada a counter() incrementa ese mismo valor retenido, así que las llamadas muestran primero 1 y luego 2. El valor es privado, mientras que counter es la interfaz pública. Para crear un estado independiente, llama a otra función fábrica que cree y devuelva un cierre nuevo; llamar a este counter solo incrementa el estado que ya conserva. Si quien llama necesita reiniciar o consultar el contador, devuelve un objeto pequeño con métodos explícitos en lugar de exponer el propio vínculo.
Por qué evitar arguments.callee
arguments.callee hace referencia a la función que se está ejecutando a través de su objeto de argumentos. Algunos patrones antiguos lo usaban para asignar una propiedad a esa función, de forma parecida a una propiedad de una función con nombre. Es una técnica heredada y está prohibida en modo estricto, por lo que el código que la usa puede fallar cuando se aplica ese modo, incluidos los módulos ECMAScript. Las funciones con nombre expresan la relación con mayor claridad, y los cierres permiten mantener estado privado sin depender de esta propiedad restringida. Para el código nuevo, prefiere alguno de los patrones compatibles explicados arriba en lugar de basarte en arguments.callee.