JavaScript
Map
Explica Map como colección clave-valor con claves de cualquier tipo, orden de inserción, búsquedas, iteración, agrupación y referencias fuertes.
- Última actualización
- Actualizada
- Nivel
- Fundamentos
- Fundamentos de programación
JavaScript
Explica Map como colección clave-valor con claves de cualquier tipo, orden de inserción, búsquedas, iteración, agrupación y referencias fuertes.
Un Map es una colección de pares clave-valor donde la clave puede ser cualquier valor de JavaScript.
const productsById = new Map();
productsById.set("product-1", {
name: "Keyboard",
price: 120,
});
productsById.get("product-1");Vacío:
const map = new Map();Desde un iterable de pares [clave, valor]:
const roles = new Map([
["owner", "Propietario"],
["cashier", "Cajero"],
]);Cada elemento de entrada debe poder interpretarse como un par.
new Map([
["theme", "dark"],
["language", "es"],
]);const settings = new Map();
settings.set("theme", "dark");
settings.set("language", "es");Si la clave ya existe, se reemplaza su valor.
settings.set("theme", "light");set retorna el mismo Map, por lo que permite encadenamiento.
const settings = new Map()
.set("theme", "dark")
.set("language", "es");settings.get("theme"); // "dark"Si no existe la clave:
settings.get("timezone"); // undefinedExiste una ambigüedad cuando undefined es un valor guardado.
settings.set("timezone", undefined);
settings.get("timezone"); // undefinedPara comprobar existencia utiliza has.
settings.has("timezone"); // truesettings.delete("theme");delete retorna un booleano indicando si existía una entrada eliminable.
settings.delete("missing"); // falsePara retirar todas las entradas:
settings.clear();settings.size;size es una propiedad, no una función.
settings.size(); // TypeErrorEn un objeto normal:
const object = {};
object[1] = "one";
object["1"] = "updated";
Object.keys(object); // ["1"]Ambas claves se convierten al mismo string.
En un Map:
const map = new Map();
map.set(1, "number");
map.set("1", "string");
map.size; // 2El número 1 y el string "1" son claves distintas.
const user = {
id: "user-1",
};
const permissions = new Map();
permissions.set(user, ["read", "write"]);
permissions.get(user);La identidad de la referencia importa.
permissions.get({ id: "user-1" });
// undefinedAunque tenga las mismas propiedades, es otro objeto.
Si el dominio posee un identificador estable, una clave string puede ser más práctica para datos que deben serializarse o reconstruirse.
Map utiliza una comparación equivalente a SameValueZero.
const map = new Map();
map.set(NaN, "invalid number");
map.get(NaN); // "invalid number"También considera 0 y -0 como la misma clave.
map.set(0, "zero");
map.get(-0); // "zero"Los objetos continúan comparándose por identidad.
Un Map itera sus entradas en orden de inserción.
const map = new Map([
["first", 1],
["second", 2],
]);Actualizar el valor de una clave existente no la mueve al final.
map.set("first", 10);Eliminarla y volverla a insertar sí crea una entrada nueva al final.
El iterador predeterminado produce pares [clave, valor].
for (const [key, value] of map) {
console.log(key, value);
}Es equivalente a:
for (const entry of map.entries()) {
const [key, value] = entry;
}También existen:
map.keys();
map.values();
map.entries();Los tres retornan iteradores, no arrays.
const keys = [...map.keys()];map.forEach((value, key, currentMap) => {
console.log(key, value);
});El orden de los primeros argumentos es value, key, no key, value.
Esto sigue el estilo de Array.prototype.forEach, donde el valor aparece primero.
Un objeto suele ser apropiado cuando:
const product = {
id: "product-1",
name: "Keyboard",
};Un Map suele aportar cuando:
const productsById = new Map();No elijas Map solo por una afirmación genérica de rendimiento. Mide cuando el rendimiento sea relevante.
Desde un objeto:
const map = new Map(
Object.entries(settingsObject),
);Hacia un objeto:
const object = Object.fromEntries(map);La conversión a objeto solo conserva correctamente claves que puedan convertirse en property keys, normalmente strings o symbols.
const key = { id: 1 };
const map = new Map([[key, "value"]]);
Object.fromEntries(map);La clave objeto será convertida a string y puede perder su identidad o colisionar.
const copy = new Map(original);Crea otra colección exterior, pero las claves y valores que son objetos siguen compartidos.
copy !== original; // true
copy.get(key) === original.get(key); // trueEs una copia superficial de las entradas.
const ordersByCustomer = Map.groupBy(
orders,
(order) => order.customer,
);La clave retornada por el callback conserva su identidad y puede ser un objeto.
ordersByCustomer.get(customer);Cada valor del Map resultante es un array con los elementos del grupo.
Usa Object.groupBy cuando las claves se expresan mejor como nombres de propiedad; usa Map.groupBy cuando necesitas claves de cualquier tipo.
ECMAScript 2026 incorpora métodos para inicializar únicamente cuando una clave no existe.
const items = map.getOrInsert(
key,
defaultValue,
);La versión calculada ejecuta una función solo cuando necesita crear el valor.
const items = map.getOrInsertComputed(
key,
() => createValue(key),
);Esto evita el patrón repetido:
if (!map.has(key)) {
map.set(key, createValue(key));
}
const value = map.get(key);Son APIs recientes. Comprueba el soporte de tu runtime o herramientas de compilación antes de utilizarlas en producción.
const productsById = new Map(
products.map((product) => [
product.id,
product,
]),
);Después:
productsById.get(productId);Esto expresa una relación clave-valor directa y evita buscar repetidamente en el array.
El costo de crear el índice tiene sentido cuando se realizarán suficientes consultas o cuando el mapa es la estructura principal del dominio.
const wordCounts = new Map();
for (const word of words) {
wordCounts.set(
word,
(wordCounts.get(word) ?? 0) + 1,
);
}Con una API de inicialización disponible:
for (const word of words) {
const count = wordCounts.getOrInsert(
word,
0,
);
wordCounts.set(word, count + 1);
}const cache = new Map();
cache.set(object, result);Mientras el Map y la entrada sigan accesibles, la clave y el valor también pueden permanecer accesibles para el garbage collector.
Un Map no elimina automáticamente entradas antiguas ni limita su tamaño.
Una cache real puede necesitar:
Si quieres asociar metadatos a objetos sin impedir su recolección, considera WeakMap.
JSON.stringify(new Map([
["theme", "dark"],
]));
// "{}"JSON no serializa las entradas de un Map automáticamente.
Puedes elegir una representación.
Como pares:
JSON.stringify([...map]);Como objeto, solo cuando las claves son compatibles:
JSON.stringify(Object.fromEntries(map));Al reconstruir:
const map = new Map(
JSON.parse(serializedEntries),
);Define el formato como parte del contrato; no asumas que la identidad de claves objeto sobrevivirá a JSON.
class SessionRegistry {
#sessions = new Map();
register(session) {
this.#sessions.set(session.id, session);
}
find(sessionId) {
return this.#sessions.get(sessionId) ?? null;
}
remove(sessionId) {
return this.#sessions.delete(sessionId);
}
get size() {
return this.#sessions.size;
}
}El Map representa un registro dinámico indexado por ID.
get(key) === undefined con ausencia segura.forEach recibe value antes de key.map.keys() retorna un array.Map para una entidad con propiedades fijas y acceso por punto más claro.Map guarda pares clave-valor con claves de cualquier tipo.get puede ser ambiguo; has comprueba existencia.[key, value].forEach recibe (value, key, map).Map.groupBy permite agrupar mediante claves de cualquier tipo.¿Por qué la segunda lectura devuelve undefined?
const key = { id: 1 };
const map = new Map([[key, "value"]]);
map.get(key);
map.get({ id: 1 });La primera llamada utiliza la misma referencia guardada como clave. La segunda crea otro objeto; tener las mismas propiedades no le da la misma identidad.
Set representa una colección ordenada de valores únicos y ofrece operaciones de conjuntos.