What is an enum class in C++?

Cómo Definir Enums en JavaScript: Guía Completa

14/12/2014

Valoración: 4.26 (5944 votos)

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.

What is an enum in JavaScript?
An enum is a special type that represents a group of constants (unchangeable values). To create an enum, use the enum keyword, followed by the name of the enum, and separate the enum items with a comma: Note that the last item does not need a comma. It is not required to use uppercase, but often considered as good practice.

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.

Índice de Contenido

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? false

El 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: false

La 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 como 2, 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.

What is an enum class in C++?
In C++, enum class is a slight strengthening of the compiler checking compared to plain old enums. Unlike conventional enums, enum classes cannot be implicitly converted to int, preventing errors when an enumeration is not meant to act as an integer.
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: 6

Para 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? false

Este 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étodoVentajasDesventajasCaso de Uso Ideal
Objeto SimpleFá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.

Subir