14/12/2014
Una de las preguntas más comunes para quienes vienen de lenguajes como C++, Java o TypeScript es: ¿cómo puedo definir un enum en JavaScript? La respuesta corta y directa es que JavaScript, en su especificación nativa (ECMAScript), no incluye una palabra clave enum. Sin embargo, la ausencia de una sintaxis dedicada no significa que no podamos implementar este patrón tan útil. De hecho, existen varias formas robustas y eficientes de simular enumeraciones para mejorar la legibilidad y mantenibilidad de nuestro código.

El concepto de una enumeración, o enum, es simple: es un tipo de dato definido por el usuario que consiste en un conjunto de constantes con nombre. En lugar de usar números o cadenas de texto "mágicos" a lo largo de tu aplicación (por ejemplo, if (status === 1)), puedes usar constantes descriptivas (if (status === Status.APROBADO)), haciendo que tu código sea auto-documentado y menos propenso a errores.
El Método Más Común: Objetos de JavaScript
La forma más sencilla y extendida de crear un enum en JavaScript es utilizando un objeto plano. Simplemente declaras un objeto cuyas claves son los nombres de las constantes y cuyos valores son los datos que representarán.
Veamos un ejemplo básico para representar los días de la semana:
const DiasDeLaSemana = { DOMINGO: 0, LUNES: 1, MARTES: 2, MIERCOLES: 3, JUEVES: 4, VIERNES: 5, SABADO: 6 };Ahora, en lugar de recordar qué número corresponde a cada día, puedes usar el objeto DiasDeLaSemana para hacer tu código más claro:
function esFinDeSemana(dia) { return dia === DiasDeLaSemana.SABADO || dia === DiasDeLaSemana.DOMINGO; } let hoy = DiasDeLaSemana.LUNES; console.log(`¿Hoy es fin de semana? ${esFinDeSemana(hoy)}`); // Salida: ¿Hoy es fin de semana? falseEl Problema: La Mutabilidad
Este enfoque es simple y efectivo, pero tiene una debilidad importante: los objetos en JavaScript son mutables. Esto significa que, por accidente (o intencionadamente), alguien podría modificar tu "enum" en tiempo de ejecución, causando errores inesperados y difíciles de depurar.
// Alguien podría hacer esto en otra parte del código DiasDeLaSemana.LUNES = 100; // ¡Ups! Hemos roto la lógica let manana = 1; console.log(manana === DiasDeLaSemana.LUNES); // Salida: falseLa Solución Robusta: `Object.freeze()`
Para solucionar el problema de la mutabilidad y crear un enum verdaderamente constante, podemos utilizar el método Object.freeze(). Este método "congela" un objeto, impidiendo que se le añadan nuevas propiedades, que se eliminen propiedades existentes o que se modifiquen las propiedades existentes.
Nuestra implementación ahora se convierte en la práctica recomendada:
const StatusPedido = Object.freeze({ PENDIENTE: 'PENDIENTE', PROCESANDO: 'PROCESANDO', ENVIADO: 'ENVIADO', ENTREGADO: 'ENTREGADO', CANCELADO: 'CANCELADO' });Con este cambio, cualquier intento de modificar el objeto lanzará un error en modo estricto ('use strict';) o simplemente será ignorado silenciosamente en modo no estricto. En cualquier caso, nuestro enum está a salvo.
// Este intento de modificación fallará StatusPedido.PENDIENTE = 'NUEVO_ESTADO'; console.log(StatusPedido.PENDIENTE); // Salida: 'PENDIENTE'¿Valores Numéricos o Cadenas de Texto?
En el ejemplo anterior usamos cadenas de texto como valores. Esta es a menudo una buena elección por varias razones:
- Depuración (Debugging): Si imprimes el valor en la consola, verás
'ENVIADO'en lugar de un número como2, lo cual es mucho más informativo. - Legibilidad: El valor en sí mismo es descriptivo.
Sin embargo, los valores numéricos, como los que se usan por defecto en C++, también tienen su lugar. Pueden ser ligeramente más eficientes en términos de memoria y comparación, y son esenciales para ciertos patrones como los flags de bits.
Simulando Flags con Operadores a Nivel de Bits
Uno de los usos más potentes de los enums en lenguajes de bajo nivel como C++ es la gestión de flags. Un flag es una variable que representa un conjunto de estados booleanos (activado/desactivado). Podemos replicar este comportamiento en JavaScript utilizando valores numéricos que sean potencias de 2.
Imaginemos que estamos configurando el formato de un texto. Podemos tener negrita, cursiva y subrayado.

const FormatoTexto = Object.freeze({ NINGUNO: 0, // 000 en binario CURSIVA: 1, // 001 en binario NEGRITA: 2, // 010 en binario SUBRAYADO: 4 // 100 en binario });Gracias a que cada valor ocupa una posición de bit diferente, podemos combinar múltiples formatos usando el operador OR a nivel de bits (|).
// Queremos un texto en negrita Y subrayado let miFormato = FormatoTexto.NEGRITA | FormatoTexto.SUBRAYADO; // En binario: 010 | 100 = 110 (que es 6 en decimal) console.log(miFormato); // Salida: 6Para comprobar si un formato específico está activado, usamos el operador AND a nivel de bits (&).
function tieneNegrita(formato) { return (formato & FormatoTexto.NEGRITA) === FormatoTexto.NEGRITA; } function tieneCursiva(formato) { return (formato & FormatoTexto.CURSIVA) === FormatoTexto.CURSIVA; } console.log(`¿Tiene negrita? ${tieneNegrita(miFormato)}`); // Salida: ¿Tiene negrita? true console.log(`¿Tiene cursiva? ${tieneCursiva(miFormato)}`); // Salida: ¿Tiene cursiva? falseEste patrón es increíblemente eficiente y permite almacenar múltiples opciones en un solo número, un enfoque muy útil en aplicaciones de alto rendimiento o para interactuar con ciertas APIs.
Tabla Comparativa de Métodos
Para resumir, aquí tienes una comparación de los diferentes enfoques para simular enums en JavaScript.
| Método | Ventajas | Desventajas | Caso de Uso Ideal |
|---|---|---|---|
| Objeto Simple | Fácil de escribir y entender. | Mutable, puede ser modificado accidentalmente. | Prototipos rápidos o entornos controlados. |
| Object.freeze() | Inmutable, seguro y robusto. Previene errores. | Ligeramente más verboso de escribir. | La práctica recomendada para la mayoría de aplicaciones. |
| Valores Numéricos (Flags) | Muy eficiente en memoria y rendimiento. Permite combinar estados. | Menos legible. La lógica de bits puede ser compleja. | Gestión de permisos, configuraciones de bajo nivel, gráficos (WebGL). |
| Símbolos (`Symbol`) | Garantiza valores únicos que no colisionan con ninguna cadena de texto. | No son serializables a JSON de forma nativa. | Cuando se necesita un identificador único que no debe ser confundido con un string. |
Preguntas Frecuentes (FAQ)
¿JavaScript alguna vez tendrá una palabra clave `enum`?
Aunque ha habido propuestas en el comité TC39 (el encargado de estandarizar JavaScript), hasta la fecha no hay planes concretos de añadir una palabra clave enum nativa al lenguaje. La flexibilidad de los objetos ha hecho que esta característica no sea una prioridad máxima. Sin embargo, lenguajes que compilan a JavaScript, como TypeScript, sí ofrecen soporte nativo para enums con una sintaxis muy cómoda.
¿Por qué no usar simplemente una clase con propiedades estáticas?
Usar una clase con propiedades estáticas es otra forma viable de simular un enum. El resultado es muy similar a usar Object.freeze(). La elección entre uno y otro es principalmente una cuestión de preferencia estilística. El patrón con Object.freeze() es generalmente más conciso y común en la comunidad.
¿Qué pasa con el rendimiento?
Para el 99% de las aplicaciones, la diferencia de rendimiento entre usar un objeto congelado con strings o con números es completamente insignificante. La recomendación es priorizar siempre la legibilidad y la robustez del código. Solo en escenarios de muy alto rendimiento, como desarrollo de juegos o manipulación masiva de datos, valdría la pena considerar el uso de números por razones de optimización.
Si quieres conocer otros artículos parecidos a Cómo Definir Enums en JavaScript: Guía Completa puedes visitar la categoría Juegos.
