Map y Set en JavaScript – ¿Qué son y como crearlos?
Descubre qué son Set y Map, colecciones de datos fundamentales en JavaScript que te permitirán optimizar tu código. Aprenderás para qué sirven, sus características clave y las importantes diferencias que los distinguen de los objetos y arrays tradicionales. Domina estas estructuras para gestionar datos de forma más eficiente y elegante con ejemplos super claros!!.

Índice
1. ¿Qué es un Set en JavaScript?
Un Set es un objeto integrado en JavaScript que te permite almacenar una colección de valores únicos de cualquier tipo de valor, ya sean primitivos (como números, strings, booleanos) u objetos.
Imagínalo como una bolsa donde solo puedes guardar un ejemplar de cada cosa. Si intentas meter algo que ya está dentro, simplemente se ignora.
- ¿Para qué sirve un Set?
- ¿Cuál es su principal función?
- ¿Cómo crear un Set en JavaScript? Paso a paso
- Métodos fundamentales de Set En JavaScript
- Iteración sobre un Set
1.1. ¿Para qué sirve un Set?
La utilidad principal de un Set radica en su capacidad para gestionar colecciones donde la unicidad de los elementos es fundamental.
Sirve para escenarios donde necesitas:
- ✅ Eliminar Duplicados
-
Es la forma más eficiente y elegante de eliminar repeticiones en un array. Simplemente al convertir un array en un
Sety luego volver a array, se conservan solo los valores únicos. - ✅ Verificar Rápidamente la Existencia de un Elemento
-
Los
Setpermiten consultar si un valor existe de forma extremadamente rápida conset.has(valor), mucho más eficiente que recorrer un array conincludes()oindexOf(). - ✅ Gestionar Listas sin Duplicados y sin Orden Específico
-
Aunque mantienen el orden de inserción, los
Setno están pensados para ordenar elementos como los arrays. Son ideales cuando solo importa tener una colección única de ítems. - ✅ Realizar Operaciones de Conjuntos
-
Con los
Setpodés simular operaciones matemáticas de conjuntos como:- Unión: combinar elementos sin duplicados.
- Intersección: obtener solo los elementos comunes entre dos conjuntos.
- Diferencia: elementos que están en uno pero no en otro.
1.2. ¿Cuál es su principal función?
La función principal de un Set es garantizar y mantener una colección de elementos únicos. En esencia, actúa como un «filtro de duplicados» automático y un «buscador de existencia» de alta velocidad para tus datos.
1.3. ¿Cómo crear un Set en JavaScript? Paso a paso
1.3.1. Crear un Set vacío
const conjunto = new Set();Lenguaje del código: JavaScript (javascript)
¿Qué está pasando aquí?
- Usamos el constructor
Set()para crear una nueva colección vacía de tipoSet. - El identificador
conjuntoes una variable JS que va a almacenar esa instancia delSet. - En este momento, el
Setno contiene ningún valor.
¿Para qué se usa un Set vacío?
Para luego ir agregando elementos manualmente con .add():
conjunto.add("uno");
conjunto.add("dos");
console.log(conjunto); // Set(2) { 'uno', 'dos' }Lenguaje del código: JavaScript (javascript)
NOTA!!!! Si te animas y deseas ver el resultado de este ejemplo y de todos los que iremos proporcionando directamente desde tu PC, te invito a seguir estos pasos.
- Primero, revisa el punto 5 del siguiente artículo sobre como usar e instalar VSCode (este es el editor de código mas usado), donde encontrarás los pasos para crear la estructura necesaria para visualizar una página desde tu navegador predeterminado.
- Si entendiste correctamente este paso anterior, sabrás donde colocar el código
scriptque te acabamos de proporcionar (arriba). Ahora, puedes visualizar el resultado, para ello puedes hacer lo siguiente:- Una vez abierta y visualizada la página, abre la consola del navegador presionando la tecla F12.
- Ahora, dirígete a la pestaña que dice
Console, y desde aquí podrás ver el resultado del script que hayamos introducido anteriormente.
- No te preocupes, estos pasos son más simples de lo que parecen!!!! Entonces… cada vez que dejemos un código de ejemplo como éste, puedes seguir estos pasos y ver los resultados por ti mismo. ¡Ojalá te animes!!!!
1.3.2. Crear un Set con valores iniciales
La forma más común y potente de crear un Set es pasándole un iterable (como un Array, un String, u otro Set) al constructor. El Set automáticamente extraerá los valores de ese iterable y los añadirá a sí mismo, ¡eliminando cualquier duplicado en el proceso!
// EJEMPLO: Inicializar un Set con un Array
const frutas = ["manzana", "banana", "naranja", "manzana", "kiwi"]; // Esto es un array
const setDeFrutas = new Set(frutas); // Aquí lo convertimos a Set
console.log("Array original de frutas:", frutas);
// Salida: Array original de frutas: [ 'manzana', 'banana', 'naranja', 'manzana', 'kiwi' ]
console.log("Set de frutas (duplicados eliminados):", setDeFrutas);
// Salida: Set de frutas (duplicados eliminados): Set(4) { 'manzana', 'banana', 'naranja', 'kiwi' }
// Observa que 'manzana' aparece solo una vez en el Set.
Lenguaje del código: JavaScript (javascript)
Explicación del Código:
const frutas = ["manzana", ...];:- Definimos un array
frutasque contiene algunos duplicados ("manzana").
- Definimos un array
const setDeFrutas = new Set(frutas);:- Aquí, pasamos el array
frutas(que es un iterable) directamente al constructorSet(). ElSetrecorre internamente el array y añade cada elemento. Como la"manzana"se intenta añadir por segunda vez, elSetla ignora porque su principal función es la unicidad de los elementos.
- Aquí, pasamos el array
- El
setDeFrutasresultante:- Contiene solo los elementos únicos del array original.
1.3.3. ¿Qué tipos de valores se pueden usar?
Los Set pueden almacenar cualquier tipo de dato primitivo o referencial, por ejemplo:
🔸 Con strings
const letras = new Set(["a", "b", "c", "a"]);
console.log(letras); // Set(3) { 'a', 'b', 'c' }Lenguaje del código: JavaScript (javascript)
🔸 Con booleanos
const valores = new Set([true, false, true]);
console.log(valores); // Set(2) { true, false }Lenguaje del código: JavaScript (javascript)
🔸 Con objetos
const obj1 = { nombre: "Juan" };
const obj2 = { nombre: "Juan" };
const personas = new Set([obj1, obj2]);
console.log(personas.size); // 2 (porque son objetos distintos en memoria)Lenguaje del código: JavaScript (javascript)
IMPORTANTE: Aunque obj1 y obj2 parezcan iguales, son dos objetos diferentes en memoria, por eso el Set los considera distintos.
1.3.4. Práctica usal: Crear un Set desde un array para eliminar duplicados
const lista = [10, 20, 10, 30, 40, 20]; // Este es el array
const unicos = new Set(lista); // Lo convertimos a Set
console.log(unicos); // Set(4) { 10, 20, 30, 40 } Lenguaje del código: JavaScript (javascript)
Si querés convertirlo en un array nuevamente:
const arraySinDuplicados = [...unicos];
console.log(arraySinDuplicados); // [10, 20, 30, 40]Lenguaje del código: JavaScript (javascript)
Aquí:
- Convierte el
Setde vuelta a array, usando el operador spread (...). - Obtenés un array nuevo, sin duplicados.
- Este es un método rápido y profesional para limpiar arrays.
1.4. Métodos fundamentales de Set En JavaScript
Estos métodos te permiten manipular los elementos dentro de un Set. Recordá que los Set no permiten duplicados y no tienen índices, como sí ocurre con los arrays.
1.4.1. .add(valor) → Agrega un nuevo valor
Sintaxis:
const numeros = new Set();
numeros.add(1);
numeros.add(2);
numeros.add(2); // Intento duplicado
console.log(numeros); // Set(2) { 1, 2 }Lenguaje del código: JavaScript (javascript)
Explicación:
.add(valor)agrega el valor alSetsolo si no existe aún.- El valor
2solo aparece una vez, incluso si lo agregás varias veces. - Este método es encadenable, podés hacer:
numeros.add(3).add(4).add(5);Lenguaje del código: CSS (css)
1.4.2. .delete(valor) → Elimina un valor existente
Sintaxis:
const letras = new Set(["a", "b", "c"]);
letras.delete("b"); // Elimina el valor "b"
console.log(letras); // Set(2) { 'a', 'c' }
const resultado = letras.delete("z"); // Intenta borrar algo que no existe
console.log(resultado); // falseLenguaje del código: JavaScript (javascript)
Explicación:
.delete(valor)elimina un valor si existe y devuelvetrue.- Si el valor no está en el
Set, no hace nada y devuelvefalse. - El
Setno lanza errores si tratás de borrar un valor inexistente.
1.4.3. .has(valor) → Verifica si existe un valor
Sintaxis:
const frutas = new Set(["manzana", "banana"]);
console.log(frutas.has("banana")); // true
console.log(frutas.has("pera")); // falseLenguaje del código: JavaScript (javascript)
Explicación:
.has(valor)devuelvetruesi el valor existe en elSet, yfalsesi no.- Es útil para validar si ya está incluido un valor antes de agregarlo o hacer lógica condicional.
1.4.4. .clear() → Elimina todos los valores del Set
Sintaxis:
const numeros = new Set([1, 2, 3]);
console.log(numeros.size); // 3 antes del clear
numeros.clear(); // Borra todos los valores
console.log(numeros); // Set(0) {}Lenguaje del código: JavaScript (javascript)
Explicación:
.clear()borra todos los elementos delSet.- El
Setqueda vacío, pero sigue existiendo (no se elimina la variable). - Ideal para reiniciar datos temporales, listas dinámicas, etc.
1.4.5. .size → Devuelve la cantidad de elementos
Sintaxis:
const conjunto = new Set(["x", "y", "z"]);
console.log(conjunto.size); // 3Lenguaje del código: JavaScript (javascript)
Explicación:
.sizees una propiedad (no un método), por eso no lleva paréntesis.- Equivalente a
.lengthen los arrays. - Siempre devuelve el número de elementos únicos dentro del
Set.
1.4.6. Resumen en tabla
| Método / Propiedad | ¿Qué hace? | Tipo |
|---|---|---|
.add(valor) | Agrega un valor si no existe | Método |
.delete(valor) | Elimina un valor existente | Método |
.has(valor) | Verifica si el valor está presente | Método |
.clear() | Borra todos los valores del Set | Método |
.size | Devuelve la cantidad de elementos únicos | Propiedad |
1.5. Iteración sobre un Set
¿Qué significa iterar sobre un Set?
Significa recorrer cada uno de los elementos únicos que contiene la colección, uno por uno, para realizar alguna operación con ellos. A diferencia de los arrays, donde el orden está implícitamente indexado, en un Set el concepto principal es la presencia o ausencia de un elemento.
Sin embargo, los Sets en JavaScript mantienen el orden de inserción, lo que significa que los elementos se iterarán en el mismo orden en que fueron añadidos (o en el orden en que aparecieron en el iterable inicial si se usó el constructor con un array, por ejemplo).
Las dos formas más comunes y recomendadas para iterar sobre un Set son:
- El bucle
for...of - El método
forEach().
1.5.1. for...of Loop
El bucle for...of es la forma más moderna y sencilla de iterar sobre cualquier iterable en JavaScript, y los Sets son iterables. Proporciona una manera directa de obtener cada valor del Set en cada iteración.
// Creamos un Set de nombres de estudiantes
const estudiantesActivos = new Set(["Ana", "Luis", "Sofía", "Pedro"]);
console.log("--- Iterando con for...of ---");
for (const estudiante of estudiantesActivos) {
console.log(`Hola, ${estudiante}!`);
}
/* Salida:
--- Iterando con for...of ---
Hola, Ana!
Hola, Luis!
Hola, Sofía!
Hola, Pedro!
*/
Lenguaje del código: JavaScript (javascript)
Explicación del Código:
const estudiantesActivos = new Set(["Ana", "Luis", "Sofía", "Pedro"]);: Inicializamos unSetcon cuatro nombres.for (const estudiante of estudiantesActivos) { ... }: Esta es la sintaxis del buclefor...of.const estudiante: En cada iteración, la variableestudiantetomará el valor del siguiente elemento delSet.of estudiantesActivos: Indica que estamos iterando sobre elSetllamadoestudiantesActivos.
console.log(Hola, ${estudiante}!);: Dentro del bucle, accedemos al valor actual (estudiante) y lo imprimimos en la consola.
El bucle for...of es ideal cuando solo necesitas acceder a los valores del Set y realizar una acción por cada uno.
1.5.2. forEach() método
El método forEach() es un método de instancia disponible en los Sets que te permite ejecutar una función de callback una vez por cada elemento en el Set. Es muy similar al forEach() de los arrays, pero con una pequeña peculiaridad en sus argumentos.
La función de callback que le pasas a forEach() recibe hasta tres argumentos:
value(valor actual):- El valor del elemento actual que se está procesando en el
Set.
- El valor del elemento actual que se está procesando en el
key(clave):- En el caso de un
Set, la «clave» es idéntica alvalue. Esto se debe a que losSets no tienen claves separadas como losMaps o los objetos; el valor es la clave. Este argumento está presente para mantener una firma consistente con elforEach()deMap.
- En el caso de un
set(el Set completo):- Una referencia al
Setsobre el cual se está iterando. Esto es útil si necesitas interactuar con elSetcompleto dentro del callback.
- Una referencia al
// Volvemos a usar nuestro Set de nombres de estudiantes
const estudiantesActivos = new Set(["Ana", "Luis", "Sofía", "Pedro"]);
console.log("\n--- Iterando con forEach() ---");
estudiantesActivos.forEach((valor, clave, setCompleto) => {
console.log(`Valor: ${valor}, Clave (igual al valor): ${clave}`);
// También podríamos usar setCompleto aquí si lo necesitáramos
// console.log("Set completo dentro del forEach:", setCompleto);
});
/* Salida:
--- Iterando con forEach() ---
Valor: Ana, Clave (igual al valor): Ana
Valor: Luis, Clave (igual al valor): Luis
Valor: Sofía, Clave (igual al valor): Sofía
Valor: Pedro, Clave (igual al valor): Pedro
*/
// Otro ejemplo de forEach, usando solo el valor
console.log("\n--- forEach() usando solo el valor ---");
estudiantesActivos.forEach(estudiante => {
if (estudiante.startsWith("A")) {
console.log(`${estudiante} comienza con 'A'.`);
}
});
/* Salida:
--- forEach() usando solo el valor ---
Ana comienza con 'A'.
*/
Lenguaje del código: JavaScript (javascript)
Explicación del Código:
estudiantesActivos.forEach((valor, clave, setCompleto) => { ... });: Llamamos al métodoforEach()en nuestroSet. Le pasamos una función de flecha como callback.- Dentro de la función de flecha:
valor: En cada iteración,valorcontendrá el elemento actual delSet(ej., «Ana», luego «Luis», etc.).clave: También contendrá el mismo elemento actual («Ana», «Luis», etc.). Este argumento es un vestigio de la similitud conMap.prototype.forEach().setCompleto: Contendrá una referencia alSetestudiantesActivosen sí.
console.log(...): Imprimimos los valores para demostrar lo que cada argumento contiene.
El método forEach() es útil cuando necesitas una mayor flexibilidad, como acceder al Set completo dentro del callback, o si estás acostumbrado a su uso en arrays. Sin embargo, para la mayoría de los casos donde solo necesitas el valor, el for...of es a menudo más conciso y legible.
2. ¿Qué es un Map en JavaScript?
Un Map es una colección ordenada de pares clave-valor donde tanto las claves como los valores pueden ser de cualquier tipo de dato. Esto incluye tipos primitivos (strings, números, booleanos, null, undefined) y, crucialmente, objetos (incluyendo funciones y otros Maps o Sets).
A primera vista, esto puede sonar similar a un objeto literal ({}), pero Map ofrece ventajas cruciales y un comportamiento más robusto para ciertos escenarios.
- ¿Para qué sirve un Map?
- ¿Cuál es su función principal?
- Diferencias clave de Map con los objetos
- ¿Cómo crear un Map?
- Métodos fundamentales de Map
- Iteración sobre un Map
2.1. ¿Para qué sirve un Map?
Map es la herramienta ideal cuando necesitas asociar información de forma flexible y garantizar un orden específico.
Sirve para escenarios donde:
- ✅ Necesitás usar cualquier tipo de dato como clave
-
A diferencia de los objetos literales, cuyas claves se convierten automáticamente a strings (salvo los
Symbol), unMapte permite usar objetos, funciones o inclusoNaNcomo claves distintas. Esto es invaluable cuando tus datos no se pueden representar convenientemente con claves de tipo string. - ✅ El orden de inserción de los elementos es importante
-
Los
Maprecuerdan el orden exacto en que se insertaron los pares clave-valor. Al iterar sobre unMap, los elementos aparecen en ese mismo orden. Esto no está garantizado de la misma forma con los objetos literales, especialmente en versiones antiguas de JavaScript. - ✅ Realizás frecuentes adiciones y eliminaciones de pares clave-valor
-
Los
Mapestán optimizados para agregar y eliminar elementos, lo que les da un rendimiento predecible y eficiente en operaciones dinámicas. - ✅ Necesitás saber fácilmente el número de elementos
-
Los
Mapincluyen una propiedadsizeque te da directamente la cantidad de pares clave-valor contenidos. No es necesario calcularla manualmente como ocurre con los objetos usandoObject.keys().length.
2.2. ¿Cuál es su función principal?
La función principal de un Map es proporcionar un mecanismo robusto y flexible para almacenar y gestionar colecciones de pares clave-valor, donde la flexibilidad en los tipos de claves y el mantenimiento del orden de inserción son cruciales.
Actúa como un diccionario o tabla de búsqueda altamente eficiente que no está limitado por las restricciones de los objetos literales en cuanto a los tipos de claves y el orden de los elementos.
2.3. Diferencias clave de Map con los objetos
| Característica | Object | Map |
|---|---|---|
| Claves | Solo strings o symbols | Cualquier tipo de dato |
| Orden de elementos | No garantizado | Conserva el orden de inserción |
| Iteración | No directamente iterable | Totalmente iterable |
Tamaño (.length o .size) | No tiene .length | Tiene .size |
| Optimizado para | Acceso y estructuras genéricas | Rendimiento en operaciones frecuentes de clave/valor |
2.4. ¿Cómo crear un Map?
Hay dos formas principales de hacerlo, similar a cómo se trabaja con los Sets.
2.4.1. Crear un Map vacío: new Map()
La forma más básica es invocar al constructor Map() sin ningún argumento. Esto te da un Map inicialmente vacío al que puedes añadir pares clave-valor más tarde usando el método set().
// Paso 1: Declarar un Map vacío
const miPrimerMap = new Map();
console.log("miPrimerMap (vacío):", miPrimerMap);
// Salida: miPrimerMap (vacío): Map(0) {}
// La salida muestra un objeto Map con 0 elementos.
Lenguaje del código: JavaScript (javascript)
Explicación del código:
const miPrimerMap = new Map();:console.log("miPrimerMap (vacío):", miPrimerMap);:- Al imprimir la variable
miPrimerMap, la consola muestra que es un objetoMapy que su tamaño actual es 0.
- Al imprimir la variable
2.4.2. Inicializar un Map con un array de pares [key, value]
Esta es la forma más común y efectiva de crear un Map si ya tienes los datos que deseas almacenar. Puedes pasarle al constructor Map() un iterable (generalmente un array) donde cada elemento del iterable es a su vez un array de dos elementos: el primero es la clave y el segundo es el valor.
El Map procesa estos «pares» y los añade directamente a la colección. Si hay claves duplicadas en el array inicial, el último valor asociado a esa clave será el que prevalezca.
// Ejemplo 1: Inicializar un Map con un array de arrays [clave, valor]
const datosDeUsuarios = [
["id_001", { nombre: "Ana", edad: 28 }],
["id_002", { nombre: "Luis", edad: 34 }],
["id_003", { nombre: "Sofía", edad: 22 }]
];
const mapaUsuarios = new Map(datosDeUsuarios);
console.log("Array original de datos de usuarios:", datosDeUsuarios);
/* Salida:
Array original de datos de usuarios: [
[ 'id_001', { nombre: 'Ana', edad: 28 } ],
[ 'id_002', { nombre: 'Luis', edad: 34 } ],
[ 'id_003', { nombre: 'Sofía', edad: 22 } ]
]
*/
console.log("Map de usuarios creado:", mapaUsuarios);
/* Salida:
Map de usuarios creado: Map(3) {
'id_001' => { nombre: 'Ana', edad: 28 },
'id_002' => { nombre: 'Luis', edad: 34 },
'id_003' => { nombre: 'Sofía', edad: 22 }
}
*/
Lenguaje del código: JavaScript (javascript)
Explicación del código:
const datosDeUsuarios = [ ... ];:- Definimos un array llamado
datosDeUsuarios. Cada elemento de este array es, a su vez, un pequeño array de dos elementos ([clave, valor]). Aquí, las claves son strings (IDs) y los valores son objetos con información del usuario.
- Definimos un array llamado
const mapaUsuarios = new Map(datosDeUsuarios);:- Pasamos
datosDeUsuariosdirectamente al constructorMap(). El constructor itera sobredatosDeUsuariosy para cada mini-array[clave, valor], añade ese par almapaUsuarios.
- Pasamos
- El
mapaUsuariosresultante:- Contiene los tres pares clave-valor, manteniendo el orden en que fueron definidos en el array original.
2.5. Métodos fundamentales de Map
2.5.1. .set(clave, valor)
Agrega un nuevo par clave/valor o actualizar el valor de una clave existente.
const mapa = new Map();
mapa.set("nombre", "Juan");
mapa.set("edad", 30);
console.log(mapa);
// Map(2) { 'nombre' => 'Juan', 'edad' => 30 }Lenguaje del código: JavaScript (javascript)
Explicación:
- Si la clave no existe, la agrega.
- Si ya existe, simplemente actualiza el valor.
- Este método retorna el
Mapactualizado, lo que permite el encadenamiento (chaining).
2.5.2. .get(clave)
Obtener el valor asociado a una clave específica.
const persona = new Map();
persona.set("nombre", "Lucía");
console.log(persona.get("nombre"));
// "Lucía"
console.log(persona.get("edad"));
// undefined (porque no existe esa clave)Lenguaje del código: JavaScript (javascript)
Explicación:
- Retorna el valor correspondiente a la clave.
- Si la clave no existe, retorna
undefined.
2.5.3. .has(clave)
Verificar si una clave existe en el Map.
const inventario = new Map([
["manzanas", 10],
["naranjas", 5]
]);
console.log(inventario.has("manzanas")); // true
console.log(inventario.has("bananas")); // falseLenguaje del código: JavaScript (javascript)
Explicación:
- Retorna
truesi la clave está presente en el Map. - Muy útil para validaciones previas.
2.5.4. .delete(clave)
Eliminar un par clave/valor del Map.
const mapa = new Map([
["color", "rojo"],
["forma", "círculo"]
]);
mapa.delete("color");
console.log(mapa);
// Map(1) { 'forma' => 'círculo' }Lenguaje del código: JavaScript (javascript)
Explicación:
- Elimina el par correspondiente a la clave.
- Devuelve
truesi lo eliminó correctamente,falsesi la clave no existía.
2.5.5. .clear()
Eliminar todos los pares clave/valor del Map.
const datos = new Map([
["clave1", "valor1"],
["clave2", "valor2"]
]);
datos.clear();
console.log(datos);
// Map(0) {}Lenguaje del código: JavaScript (javascript)
Explicación:
- Borra todo el contenido del Map.
- Es útil para reiniciar estructuras de datos.
2.5.6. .size
Saber cuántos pares clave/valor hay en el Map.
const mapa = new Map();
mapa.set("x", 100);
mapa.set("y", 200);
console.log(mapa.size);
// 2Lenguaje del código: JavaScript (javascript)
Explicación:
- Propiedad (no método) que indica cuántos pares contiene el Map.
- Se accede sin paréntesis.
2.6. Iteración sobre un Map
Iterar sobre un Map significa recorrer cada uno de los pares clave-valor que contiene, uno por uno, para realizar alguna operación o acceder a su información. A diferencia de los Sets que solo tienen valores únicos, los Maps manejan tanto una clave como un valor asociado.
RECIUERDA! Los Maps en JavaScript, al igual que los Sets, mantienen el orden de inserción, lo que significa que los elementos se iterarán en el mismo orden en que fueron añadidos.
Hay varias formas de iterar sobre un Map, cada una útil para diferentes escenarios:
for...ofconentries(),keys(),values()forEach()método
2.6.1. for...of con entries(), keys(), values()
El bucle for...of es la forma más moderna y versátil de iterar sobre cualquier iterable en JavaScript. Los Maps ofrecen métodos específicos que devuelven iteradores para sus entradas, claves o valores.
a) map.entries(): ITERAR SOBRE PARES [clave, valor]
Este es el comportamiento predeterminado cuando se itera directamente sobre un Map con for...of. El método entries() devuelve un objeto iterable que contiene un array [clave, valor] para cada par en el Map.
Usando la desestructuración de arrays en el bucle for...of, puedes acceder directamente a la clave y al valor.
// Creamos un Map de puntuaciones de jugadores
const puntuacionesJugadores = new Map([
["Ana", 150],
["Luis", 200],
["Sofía", 180],
]);
console.log("--- Iterando sobre pares [clave, valor] con for...of y entries() ---");
// Puedes omitir .entries() ya que es el comportamiento por defecto de for...of en Map
for (const [nombre, puntuacion] of puntuacionesJugadores.entries()) {
console.log(`${nombre} tiene ${puntuacion} puntos.`);
}
/* Salida:
--- Iterando sobre pares [clave, valor] con for...of y entries() ---
Ana tiene 150 puntos.
Luis tiene 200 puntos.
Sofía tiene 180 puntos.
*/
Lenguaje del código: JavaScript (javascript)
Explicación del código:
const puntuacionesJugadores = new Map([...]);: Inicializamos unMapcon algunos nombres de jugadores y sus puntuaciones.for (const [nombre, puntuacion] of puntuacionesJugadores.entries()) { ... }:puntuacionesJugadores.entries(): Este método devuelve un objeto iterable. Cada vez que el bucle pide el siguiente elemento, este iterable proporciona un array de dos elementos:[clave, valor].const [nombre, puntuacion]: Aquí usamos la desestructuración de arrays. En cada iteración, el primer elemento del array ([clave, valor]) se asigna a la variablenombre, y el segundo elemento se asigna apuntuacion. Esto hace que el código sea muy legible.
console.log(...): Dentro del bucle, utilizamos las variablesnombreypuntuacionpara mostrar la información de cada jugador.
b) map.keys(): ITERAR SOBRE LAS CLAVES
El método keys() devuelve un objeto iterable que contiene SOLO las claves de cada par clave-valor en el Map.
const productosEnStock = new Map([
["Laptop", 10],
["Teclado", 50],
["Mouse", 100],
]);
console.log("\n--- Iterando sobre las claves con for...of y keys() ---");
for (const nombreProducto of productosEnStock.keys()) {
console.log(`Producto disponible: ${nombreProducto}`);
}
/* Salida:
--- Iterando sobre las claves con for...of y keys() ---
Producto disponible: Laptop
Producto disponible: Teclado
Producto disponible: Mouse
*/
Lenguaje del código: JavaScript (javascript)
Explicación del código:
productosEnStock.keys(): Este método retorna un iterable que, en cada paso, proporciona solo la clave del siguiente par delMap.for (const nombreProducto of productosEnStock.keys()) { ... }: La variablenombreProductorecibe la clave de cada iteración.- Este enfoque es útil cuando solo te interesa la lista de las claves en tu
Mapy no sus valores asociados.
c) map.values(): ITERAR SOBRE LOS VALORES
El método values() devuelve un objeto iterable que contiene SOLO los valores de cada par clave-valor en el Map.
const temperaturasCiudades = new Map([
["Buenos Aires", 25],
["Madrid", 30],
["Londres", 18],
]);
console.log("\n--- Iterando sobre los valores con for...of y values() ---");
for (const temperatura of temperaturasCiudades.values()) {
console.log(`Una temperatura registrada: ${temperatura}°C`);
}
/* Salida:
--- Iterando sobre los valores con for...of y values() ---
Una temperatura registrada: 25°C
Una temperatura registrada: 30°C
Una temperatura registrada: 18°C
*/
Lenguaje del código: JavaScript (javascript)
Explicación del código:
temperaturasCiudades.values(): Este método retorna un iterable que, en cada paso, proporciona solo el valor del siguiente par delMap.for (const temperatura of temperaturasCiudades.values()) { ... }: La variabletemperaturarecibe el valor de cada iteración.- Este método es ideal cuando solo necesitas procesar los valores almacenados en el
Mapy las claves no son relevantes para la tarea actual.
2.6.2. forEach() método
El método forEach() es un método de instancia que te permite ejecutar una función de callback una vez por cada par clave-valor en el Map. Es similar al forEach() de los arrays y Sets, pero sus argumentos para el callback están específicamente diseñados para Maps.
La función de callback que le pasas a forEach() recibe hasta tres argumentos en un orden específico:
value(valor actual): El valor del elemento actual que se está procesando.key(clave actual): La clave del elemento actual que se está procesando.map(el Map completo): Una referencia alMapsobre el cual se está iterando. Esto es útil si necesitas interactuar con elMapcompleto (por ejemplo, acceder a otros elementos) dentro del callback
const usuariosConRoles = new Map([
["[email protected]", "Administrador"],
["[email protected]", "Editor"],
["[email protected]", "Espectador"],
]);
console.log("\n--- Iterando con forEach() ---");
usuariosConRoles.forEach((rol, email, mapCompleto) => {
console.log(`Email: ${email}, Rol: ${rol}`);
// Opcional: usar mapCompleto si lo necesitas dentro del callback
// console.log("Tamaño del Map dentro del forEach:", mapCompleto.size);
});
/* Salida:
--- Iterando con forEach() ---
Email: [email protected], Rol: Administrador
Email: [email protected], Rol: Editor
Email: [email protected], Rol: Espectador
*/
// Otro ejemplo de forEach, usando solo los argumentos que necesitas
console.log("\n--- forEach() usando solo valor y clave ---");
usuariosConRoles.forEach((rol, email) => {
if (rol === "Editor") {
console.log(`${email} tiene el rol de ${rol}.`);
}
});
/* Salida:
--- forEach() usando solo valor y clave ---
[email protected] tiene el rol de Editor.
*/
Lenguaje del código: JavaScript (javascript)
Explicación del código:
usuariosConRoles.forEach((rol, email, mapCompleto) => { ... });: Llamamos al métodoforEach()en nuestroMap. Le pasamos una función de flecha como callback.- Dentro de la función de flecha:
rol: Contendrá el valor actual del par (ej., «Administrador»).email: Contendrá la clave actual del par (ej., «[email protected]»).mapCompleto: Contendrá una referencia alMapusuariosConRolesen sí.
console.log(...): Imprimimos los valores para demostrar lo que cada argumento contiene.
3. WeakSet y WeakMap: La gestión de la memoria en JavaScript
Para entender WeakSet y WeakMap, primero necesitamos comprender un concepto fundamental en JavaScript: el Garbage Collection (recolección de basura).
¿Qué es la Garbage Collection? Concepto de referencias débiles:
En JavaScript, la gestión de la memoria es automática. El motor de JavaScript tiene un proceso llamado Garbage Collector (GC) que se encarga de liberar la memoria ocupada por objetos que ya no son «alcanzables» o «referenciados» por ninguna parte de tu código. Esto evita que tu aplicación consuma demasiada memoria y sufra de «fugas de memoria» (memory leaks).
Cuando tienes una referencia «fuerte» a un objeto, significa que mientras esa referencia exista en tu código, el Garbage Collector no puede liberar la memoria ocupada por ese objeto, incluso si no lo estás usando activamente en ese momento. Los Arrays, Sets y Maps normales crean referencias fuertes a sus elementos o claves/valores.
Las referencias débiles son diferentes. Una referencia débil a un objeto no impide que el Garbage Collector libere la memoria de ese objeto si no hay otras referencias fuertes apuntando a él. Si el objeto es recolectado, la entrada en la colección débil (WeakSet/WeakMap) simplemente desaparece automáticamente.
¿Por qué es importante el Garbage Collection?
Es vital para la eficiencia y estabilidad de tu aplicación. Si tu código crea objetos y mantiene referencias a ellos indefinidamente sin necesitarlos, la memoria se acumulará, haciendo que tu aplicación se vuelva más lenta o incluso se bloquee. Las referencias débiles son una herramienta avanzada para manejar ciertos escenarios de memoria donde no quieres que la presencia de un objeto en una colección impida su recolección.
3.1. WeakSet: Colecciones débiles de objetos únicos
Un WeakSet es una colección de objetos únicos. Su característica principal es que las referencias a los objetos que contiene son débiles.
- Solo puede contener objetos:
- No puedes almacenar valores primitivos (strings, números, booleanos,
null,undefined) en unWeakSet. Solo acepta objetos.
- No puedes almacenar valores primitivos (strings, números, booleanos,
- No es iterable:
- No puedes usar
for...ofoforEach()para recorrer los elementos de unWeakSet. Tampoco tiene una propiedadsize. Esto se debe a que, al ser sus referencias débiles, los elementos podrían desaparecer en cualquier momento si el GC actúa, lo que haría que la iteración fuera impredecible.
- No puedes usar
- Propósito:
- Mantener un registro de objetos sin crear referencias fuertes. Si un objeto solo está referenciado por un
WeakSet(y ninguna otra parte del código tiene una referencia fuerte a él), puede ser recolectado por el GC. Cuando el objeto es recolectado, se elimina automáticamente delWeakSet.
- Mantener un registro de objetos sin crear referencias fuertes. Si un objeto solo está referenciado por un
MÉTODOS CLAVE DE WeakSet:
add(value): Añade un objeto alWeakSet.delete(value): Elimina un objeto delWeakSet.has(value): Verifica si un objeto está presente en elWeakSet.
CASOS DE USO DE WeakSet:
- Marcar objetos ya procesados o visitados: Imagina un algoritmo que debe procesar una lista de objetos y no quieres procesar el mismo objeto dos veces. Un
WeakSetpuede servir como un registro de «objetos ya vistos». Si un objeto se sale de alcance y es recolectado, no hay problema, porque ya no lo necesitamos.- Ejemplo:
let obj1 = { id: 1 };
let obj2 = { id: 2 };
let obj3 = { id: 3 };
const objetosProcesados = new WeakSet();
objetosProcesados.add(obj1);
objetosProcesados.add(obj2);
console.log("¿Obj1 procesado?", objetosProcesados.has(obj1)); // Salida: ¿Obj1 procesado? true
console.log("¿Obj3 procesado?", objetosProcesados.has(obj3)); // Salida: ¿Obj3 procesado? false
// Si obj1 ya no es referenciado en ningún otro lugar, el GC puede eliminarlo.
// Cuando lo haga, obj1 se eliminará automáticamente de 'objetosProcesados'.
obj1 = null; // Quita la referencia fuerte a obj1
// En un entorno de navegador/Node.js, el GC eventualmente actuará.
// No podemos verificar inmediatamente si ha sido recolectado,
// ya que el GC es no determinista.
// Sin embargo, sabemos que la referencia del WeakSet no lo retiene.Lenguaje del código: JavaScript (javascript)
Explicación: objetosProcesados guarda referencias débiles a obj1 y obj2. Cuando obj1 = null se ejecuta, si obj1 no tiene otras referencias fuertes, se vuelve elegible para ser recolectado. El WeakSet no impide esto.
- Gestionar un registro de instancias de una clase: Útil para saber qué instancias de una clase particular están «vivas» sin impedir que se destruyan cuando ya no se necesitan.
- Ejemplo:
class ComponenteUI {
constructor(name) {
this.name = name;
ComponenteUI.activeInstances.add(this); // Añadir esta instancia al WeakSet
console.log(`Componente ${this.name} creado.`);
}
destroy() {
ComponenteUI.activeInstances.delete(this); // Eliminar del WeakSet
console.log(`Componente ${this.name} destruido.`);
// Aquí podrías nullificar otras referencias fuertes si las hubiera
}
static activeInstances = new WeakSet(); // Un WeakSet para todas las instancias activas
}
let btn1 = new ComponenteUI("Botón Guardar");
let btn2 = new ComponenteUI("Botón Cancelar");
console.log("¿Botón Guardar está en instancias activas?", ComponenteUI.activeInstances.has(btn1)); // true
console.log("¿Botón Cerrar está en instancias activas?", ComponenteUI.activeInstances.has(new ComponenteUI("Botón Cerrar"))); // false (porque es una nueva instancia temporal)
// Cuando btn1 se establece a null, puede ser recolectado, y el WeakSet lo liberará automáticamente.
btn1 = null;
// (El GC se encargará, no podemos hacer un console.log inmediato para verificar la recolección)Lenguaje del código: JavaScript (javascript)
Explicación: El WeakSet ComponenteUI.activeInstances mantiene un registro de las instancias ComponenteUI. Si btn1 ya no es referenciado en ningún otro lugar de tu código (por ejemplo, si su elemento DOM asociado fuera eliminado y no hubiera otras variables apuntando a él), el GC puede limpiarlo, y automáticamente desaparecerá del WeakSet, sin que tengas que gestionarlo manualmente.
3.2. WeakMap: Colecciones débiles de Clave-Valor con claves de objeto
Un WeakMap es una colección de pares clave-valor similar a un Map, pero con dos diferencias cruciales relacionadas con las referencias débiles.
- Las claves solo pueden ser objetos:
- Al igual que
WeakSet,WeakMapno permite claves primitivas (strings, números, booleanos,null,undefined). Las claves deben ser objetos. Si una clave de objeto es recolectada por el GC, su entrada completa (clave y valor) se elimina automáticamente delWeakMap.
- Al igual que
- No es iterable:
- No puedes iterar sobre las claves o valores de un
WeakMapconfor...ofniforEach(), y no tiene una propiedadsize. Esto es por la misma razón que enWeakSet: los elementos pueden desaparecer en cualquier momento debido al GC.
- No puedes iterar sobre las claves o valores de un
- Propósito:
- Asociar datos a objetos sin crear referencias fuertes a esos objetos. Es ideal para «extender» objetos con datos adicionales que no deben impedir que el objeto original sea recolectado.
MÉTODOS CLAVE DE WeakMap:
set(key, value): Asocia unvaluea unakey(objeto).get(key): Recupera elvalueasociado a unakey.delete(key): Elimina el par clave-valor.has(key): Verifica si unakey(objeto) está presente.
CASOS DE USO DE WeakMap:
- Almacenar metadatos privados de objetos: Los
WeakMaps son perfectos para almacenar información «extra» sobre objetos que no debería ser parte del objeto en sí, y que debe ser limpiada automáticamente cuando el objeto original deja de existir. Esto es útil para implementar datos privados o «ocultos» asociados a instancias.
const _privateData = new WeakMap(); // Un WeakMap para datos privados
class Usuario {
constructor(id, nombre) {
this.id = id;
this.nombre = nombre;
// Almacenar un contador de acceso privado para este usuario
_privateData.set(this, { accessCount: 0 });
}
incrementAccessCount() {
const data = _privateData.get(this);
if (data) {
data.accessCount++;
console.log(`Contador de acceso para ${this.nombre}: ${data.accessCount}`);
}
}
getAccessCount() {
return _privateData.get(this)?.accessCount || 0;
}
}
let user1 = new Usuario(1, "Alice");
user1.incrementAccessCount(); // Contador de Alice: 1
user1.incrementAccessCount(); // Contador de Alice: 2
let user2 = new Usuario(2, "Bob");
user2.incrementAccessCount(); // Contador de Bob: 1
console.log("Contador de Alice:", user1.getAccessCount()); // Salida: Contador de Alice: 2
// Si user1 se vuelve null (pierde su referencia fuerte),
// tanto el objeto Usuario como su entrada en _privateData
// pueden ser recolectados por el GC.
user1 = null;
// No hay forma de verificar user1 en _privateData después de la recolecciónLenguaje del código: JavaScript (javascript)
Explicación: El WeakMap _privateData asocia un objeto de datos privado ({ accessCount: 0 }) a cada instancia de Usuario. La clave en el WeakMap es la propia instancia de Usuario. Si una instancia de Usuario (ej., user1) ya no es accesible por referencias fuertes en el código, el GC la liberará, y su entrada correspondiente en _privateData también se eliminará automáticamente, evitando fugas de memoria.
- Caching de resultados basados en objetos: Cuando necesitas almacenar en caché los resultados de cálculos costosos asociados a objetos específicos. Si el objeto original es recolectado, la entrada del caché asociada a él también se limpia automáticamente.
const cacheDeCalculos = new WeakMap();
function calcularComplejo(objetoDeDatos) {
if (cacheDeCalculos.has(objetoDeDatos)) {
console.log("¡Desde caché!");
return cacheDeCalculos.get(objetoDeDatos);
}
console.log("Calculando...");
// Simular un cálculo pesado
const resultado = objetoDeDatos.valor * 10 + 5;
cacheDeCalculos.set(objetoDeDatos, resultado);
return resultado;
}
let data1 = { valor: 5 };
let data2 = { valor: 10 };
console.log(calcularComplejo(data1)); // Calculando... 55
console.log(calcularComplejo(data1)); // ¡Desde caché! 55
console.log(calcularComplejo(data2)); // Calculando... 105
// Si data1 ya no es referenciado en ninguna parte,
// su entrada en cacheDeCalculos se eliminará automáticamente.
data1 = null;
// Si más tarde se crea un nuevo objeto { valor: 5 } (no la misma instancia),
// se volverá a calcular.Lenguaje del código: JavaScript (javascript)
Explicación: cacheDeCalculos almacena resultados de calcularComplejo usando el objeto de datos como clave. Cuando data1 se establece a null, si el GC lo recolecta, la entrada { data1 => 55 } se elimina del WeakMap, liberando esa memoria del caché de forma automática.
4. ¿Cuándo usar y cuándo no usar Set/Map?
Como profesional de la programación, no se trata solo de conocer las herramientas, sino de saber cuándo aplicarlas correctamente. Usar Set o Map ciegamente, cuando otras estructuras son más adecuadas, puede llevar a código más complejo, menos eficiente o difícil de entender. Aquí te explico las consideraciones clave.
4.1. ¿Cuándo NO Usar Set/Map?
Aunque Set y Map son potentes, no son la solución para todos los problemas de gestión de datos. Debes evitar usarlos en los siguientes escenarios:
- Si solo necesitas un objeto simple con claves
stringy el orden de inserción no es estrictamente crítico (o solo para claves no-numéricas): Los objetos literales ({}) son excelentes para colecciones simples de pares clave-valor donde las claves son cadenas de texto o símbolos. Son familiares para la mayoría de los desarrolladores JavaScript y a menudo más concisos de escribir para estos casos básicos. - Si solo necesitas un array para mantener un orden específico de elementos y no necesitas unicidad o mapeo complejo: Los arrays (
[]) son la estructura de datos por excelencia para listas ordenadas de elementos. Si el orden de los elementos es tu preocupación principal y los duplicados son aceptables (o se manejarán de otra forma simple), un array es la elección correcta.
4.2. ¿La elección de Set/Map mejora la legibilidad y mantenibilidad del código para otros desarrolladores?
Esta es una pregunta crucial que todo profesional debe hacerse. La respuesta es un rotundo: ¡Sí, cuando se usan en el contexto adecuado!
- Legibilidad mejorada:
- Cuando un desarrollador ve un
Set, su cerebro inmediatamente piensa: «Ah, esta es una colección de elementos únicos». La intención del código es clara sin necesidad de comentarios adicionales. Si, en cambio, usas un array y luego una lógica compleja para eliminar duplicados o verificar la unicidad, el código es más denso y menos claro a primera vista. - Cuando ven un
Map, entienden que hay una relación clave-valor donde las claves pueden ser algo más que simples strings, y que el orden de inserción se mantiene. Esto comunica que el problema que se está resolviendo requiere esa flexibilidad o garantía de orden.
- Cuando un desarrollador ve un
- Mantenibilidad mejorada:
- El código que utiliza
SetyMapde forma apropiada es generalmente más conciso y con menos errores potenciales. Menos código significa menos lugares para bugs. - Si las necesidades futuras del proyecto cambian (por ejemplo, de repente necesitas que las claves sean objetos en lugar de strings), un
Mapse adaptará fácilmente, mientras que un objeto literal requeriría una refactorización significativa. - Los métodos de
SetyMap(add,delete,has,get,set) son intuitivos y estandarizados. Un desarrollador que conoce JavaScript entenderá rápidamente lo que hace tu código.
- El código que utiliza
CONCLUSIÓN: La elección de Set y Map no es arbitraria. Responden a necesidades específicas de manejo de colecciones que los objetos literales y los arrays no cubren de forma tan elegante o eficiente. Al usarlos apropiadamente, no solo estás escribiendo código más performante, sino también más claro y fácil de mantener, lo cual es una marca de un desarrollador profesional.
5. Preguntas frecuentes y resumen sobre Set y Map en JS.
Set y Map son estructuras de datos. Set almacena valores únicos sin duplicados, mientras que Map guarda pares clave-valor con claves de cualquier tipo. Se usan para manejar datos de forma más eficiente que arrays u objetos comunes.
Set almacena solo valores únicos sin claves, mientras que Map asocia claves a valores. En Map puedes usar cualquier tipo de dato como clave; en Set, se garantiza que no haya duplicados.
Un Set se crea con new Set() y se agregan elementos con .add(valor). Ejemplo: const miSet = new Set(); miSet.add(1); miSet.add("hola");. No se permiten valores duplicados, se ignoran automáticamente.
Un Map se crea con new Map() y se agregan elementos con .set(clave, valor). Ejemplo: const miMapa = new Map(); miMapa.set('a', 1);. Las claves pueden ser objetos, funciones, números o strings.
En Set, se usa .has(valor) para comprobar si contiene un valor. En Map, se usa .has(clave) para verificar si una clave existe. Ambos métodos devuelven true o false.
Set es útil para eliminar duplicados fácilmente y verificar pertenencia con eficiencia. Map ofrece mejor rendimiento en búsquedas y permite claves de cualquier tipo, a diferencia de objetos, que limitan las claves a strings o símbolos.
Usa Set cuando necesites almacenar una colección de valores únicos y verificar rápidamente si un valor existe. Usa Map cuando necesites asociar claves a valores y acceder a ellos de forma rápida, especialmente si las claves no son strings.
