Original article: How to Use JavaScript Collections – Map and Set
En JavaScript, los objetos
son usados para almacenar múltiples valores como un conjunto de datos complejos.
Un objeto es creado con llaves {...}
y una lista de propiedades. Una propiedad es un par de clave-valor donde la clave
debe ser una cadena y el valor
puede ser de cualquier tipo.
Por otro lado, los arreglos
son una colección ordenada que puede retener datos de cualquier tipo. En JavaScript, los arreglos son creados con corchetes [...]
y permiten elementos duplicados.
Hasta ES6 (ECMAScript 2015), los objetos
y los arreglos
de JavaScript fueron las estructuras de datos más importantes para manejar colecciones de datos. La comunidad de desarrolladores no tenían muchas opciones fuera de eso. Aun así, una combinación de objetos y de arreglos permitía manejar datos en muchos escenarios.
Sin embargo, hubo unas pocas deficiencias:
- Las claves del objeto pueden ser solo de tipo
cadena
. - Los objetos no mantienen el orden de los elementos que les son agregados.
- Los objetos carecen de algunos métodos útiles, lo cual los hace más difícil de usar en algunas situaciones. Por ejemplo, no puedes computar el tamaño (
longitud
) de un objeto fácilmente. También, enumerar un objeto no es tan sencillo. - Los arreglos son colecciones de elementos que permiten duplicados. Hacer uso de arreglos que solamente tienen elementos distintos requiere lógica y código extra.
Con la introducción de ES6, recibimos dos estructuras de datos nuevas que abarcan las deficiencias mencionadas arriba: Map
y Set
. En este artículo, miraremos a ambos de cerca y entenderemos cómo usarlos en diferentes situaciones.
Map en JavaScript
Map
es una colección de pares clave-valor donde la clave puede ser de cualquier tipo. Map
recuerda el orden original en los cuales los elementos les fueron agregados, lo que significa que los datos pueden ser recuperados en el mismo orden en el que fueron insertados.
En otras palabras, Map
tiene características tanto del Objeto
como del Arreglo
:
- Como un objeto, soporta la estructura de par clave-valor.
- Como un arreglo, recuerda el orden de inserción.
Cómo crear e inicializar un Map en JavaScript
Un nuevo Map
puede ser creado así:
const map = new Map();
Lo cual regresa un Map
vacío:
Map(0) {}
Otra forma de crear un Map
es con valores iniciales. Así es cómo se crea un Map
con tres pares de clave-valor:
const freeCodeCampBlog = new Map([
['nombre', 'freeCodeCamp'],
['tipo', 'blog'],
['escritor', 'Tapas Adhikary'],
]);
Lo cual regresa un Map
con tres elementos:
Map(3) {"nombre" => "freeCodeCamp", "tipo" => "blog", "escritor" => "Tapas Adhikary"}
Cómo agregar valores a un Map en JavaScript
Para agregar un valor a Map, usamos el método set(clave, valor)
.
El método set(clave, valor)
toma dos parámetros, clave
y valor
, donde la clave y el valor pueden ser de cualquier tipo, un primitivo (boolean
, string
, number
, etc.) o un objeto:
// crea un map
const map = new Map();
// Agrega valores al map
map.set('nombre', 'freeCodeCamp');
map.set('tipo', 'blog');
map.set('escritor', 'Tapas Adhikary');
Salida:
Map(3) {"nombre" => "freeCodeCamp", "tipo" => "blog", "escritor" => "Tapas Adhikary"}
Por favor, ten en cuenta, si usas la misma clave para agregar un valor a un Map
múltiples veces, siempre lo reemplazará con el valor anterior:
// Agregar un escritor distinto
map.set('escritor', 'Alguien más!');
Así que la salida sería:
Map(3)
{"nombre" => "freeCodeCamp", "tipo" => "blog", "escritor" => "Alguien más!"}
Cómo obtener valores de un Map en JavaScript
Para obtener un valor de un Map
, usamos el método get(clave)
:
map.get('nombre'); // regresa freeCodeCamp
Todo sobre las claves de Map en JavaScript
Las claves de Map
pueden ser de cualquier tipo, un primitivo, o un objeto. Este es una de las mayores diferencias entre Map
y los objetos de JavaScript regulares donde las claves pueden ser solamente una cadena:
// crea un Map
const funMap = new Map();
funMap.set(360, 'Mi numero de casa'); // number como clave
funMap.set(true, 'Escribo blogs!'); // boolean como clave
let obj = {'nombre': 'tapas'}
funMap.set(obj, true); // object como valor
console.log(funMap);
Esta es la salida:
Map(3)
{
360 => "Mi numero de casa",
true => "Escribo blogs!",
{…} => true
}
Un objeto de JavaScript regular siempre trata a la clave como una cadena. Inclusive cuando le pasas un primitivo o un objeto, internamente convierte a la clave en una cadena:
// Crea un objeto vacío
const funObj = {};
// agrega una propiedad. Fíjate, pasando la clave como un número.
funObj[360] = 'My House Number';
// Regresa verdadero porque el número 360 se convirtió en cadena '360' internamente!
console.log(funObj[360] === funObj['360']);
Propiedades y Métodos de Map en JavaScript
El Map
de JavaScript tiene propiedades y métodos adheridos que lo hacen fácil de usar. Aquí hay algunos de los más comunes:
- Usar la propiedad
size
para saber cuántos elementos hay en unMap
. - Buscar un elemento con el método
has(clave)
. - Remover un elemento con el método
delete(clave)
. - Usar el método
clear()
para remover todos los elementos delMap
de una sola vez.
console.log('el tamaño del map es', map.size);
// regresa verdadero, si el map tiene un elemento con la clave, 'John'
console.log(map.has('John'));
// regresa falso, si el map no tiene un elemento con la clave, 'Tapas'
console.log(map.has('Tapas'));
map.delete('Sam'); // remueve el elemento con la clave, 'Sam'.
// Limpia el map removiendo todos los elementos
map.clear();
map.size // Regresará 0
Iterador de Map: keys(), values(), and entries() en JavaScript
Los métodos keys()
, values()
y entries()
regresan un MapIterator
, lo cual es excelente porque puedes usarlo en un bucle for-of
o forEach
.
Primero, crea un Map
simple:
const mapEdad = new Map([
['Jack', 20],
['Alan', 34],
['Bill', 10],
['Sam', 9]
]);
- Obtiene todas las claves.
- Obtiene todos los valores.
- Obtiene todas las entradas (pares clave-valor).
console.log(ageMap.keys());
// Salida:
// MapIterator {"Jack", "Alan", "Bill", "Sam"}
console.log(edadMap.values());
// Salida
// MapIterator {20, 34, 10, 9}
console.log(ageMap.entries());
// Salida
// MapIterator {"Jack" => 20, "Alan" => 34, "Bill" => 10, "Sam" => 9}
Cómo iterar sobre un Map en JavaScript
Puedes usar cualquiera de los bucles forEach
o for-of
para iterar sobre un Map
:
// con forEach
edadMap.forEach((value, key) => {
console.log(`${key} tiene ${value} años!`);
});
// con for-of
for(const [key, value] of edadMap) {
console.log(`${key} tiene ${value} años!`);
}
La salida va a ser el mismo en ambos casos:
Jack tiene 20 años!
Alan tiene 34 años!
Bill tiene 10 años!
Sam tiene 9 años!
Cómo convertir un Objeto en un Map en JavaScript
Podrías encontrarte con una situación donde necesitas convertir un objeto
a una estructura de tipo Map
. Puedes usar el método entries
del Objeto
para hacer eso:
const direccion = {
'Tapas': 'Bangalore',
'James': 'Huston',
'Selva': 'Srilanka'
};
const mapDirecciones = new Map(Object.entries(direccion));
Cómo convertir un Map en un Objeto en JavaScript
Si lo quieres hacer a la inversa, puedes usar el método fromEntries
:
Object.fromEntries(map)
Cómo convertir un Map en un Arreglo en JavaScript
Hay un par de maneras de convertir un map en un arreglo:
- Usando
Array.from(map)
: - Usando el operador spread:
const map = new Map();
map.set('leche', 200);
map.set("te", 300);
map.set('cafe', 500);
console.log(Array.from(map));
console.log([...map]);
Map vs. Object: ¿Cuándo deberías usarlo?
El Map
tiene características de ambos Object
y Array
. Sin embargo, Map
es más como un Object
que un Array
debido a la naturaleza de almacenar datos en el formato clave-valor
.
Aunque la similitud con los objetos termina aquí. Como has visto, el Map
es diferente en muchas maneras. Así que, ¿cuál deberías usar, y cuándo? ¿Cómo decides?
Usar Map
cuando:
- Tus necesidades no son tan sencillas. Puede que quieras crear claves que no sean cadena. Almacenar un objeto como una clave es un enfoque muy poderoso.
Map
te da esta habilidad por defecto. - Necesitas una estructura de datos donde los elementos pueden ser ordenados. Los objetos regulares no mantienen el orden de sus entradas.
- Estás buscando flexibilidad sin depender de una librería externa como lodash. Podrías terminar usando una librería como lodash porque no encontramos métodos como has(), values(), delete(), o una propiedad como size con un objeto regular. Map lo hace fácil para ti proveyendo todos estos métodos por defecto.
Usar un objeto cuando:
- No tienes ninguna de las necesidades listadas arriba.
- Dependes de
JSON.parse()
, ya que con unMap
no lo puedes convertir.
Set en JavaScript
Un Set
es una colección de elementos únicos que pueden ser de cualquier tipo. Set
es también una colección ordenada de elementos, lo que significa que esos elementos serán recuperados en el mismo orden en el que fueron insertados.
Un Set
en JavaScript se comporta de la misma manera que un set matemático.
Cómo crear e inicializar un Set en JavaScript
Un nuevo Set
puede ser creado así:
const set = new Set();
console.log(set);
Y la salida será un Set
vacío:
Set(0) {}
Así es cómo se crea un Set
con algunos valores iniciales:
const conjuntoFrutas = new Set(['?', '?', '?', '?']);
console.log(conjuntoFrutas);
Salida:
Set(4) {"?", "?", "?", "?"}
Las Propiedades y Métodos de Set en JavaScript
El Set
tiene métodos para agregar un elemento, eliminar elementos, verificar si un elemento existe, y limpiarlo completamente:
- Usa la propiedad
size
para saber el tamaño delSet
. Regresa el número de elementos. - Usa el método
add(elemento)
para agregar un elemento alSet
:
set.size
// Crea un set - setEnsalada
const setEnsalada = new Set();
// Agregar algunos vegetales
setEnsalada.add('?'); // tomate
setEnsalada.add('?'); // aguacate (o palta)
setEnsalada.add('?'); // zanahora
setEnsalada.add('?'); // pepino
console.log(setEnsalada);
// salida
// Set(4) {"?", "?", "?", "?"}
¡Me encantan los pepinos! ¿Qué te parece agregar uno más?
Oh, no, no puedo – Set
es una colección de elementos únicos:
setEnsalada.add('?');
console.log(setEnsalada);
La salida es la misma que antes – nada fue agregado al setEnsalada
.
- Usa el método
has(element)
para buscar si tenemos una zanahoria (?) o brócoli (?) en elSet
: - Usa el método
delete(element)
para quitar el aguacate (?) delSet
:
// La ensalda tiene una ?, así que regresa verdadero
console.log('¿La ensalada tiene una zanahoria?', setEnsalada.has('?'));
// La ensalada no tiene un ?, así que regresa falso
console.log('¿La ensalda tiene brócoli?', setEnsalada.has('?'));
setEnsalada.delete('?');
console.log('No me gusta ?, quitar de la ensalada:', setEnsalada);
Ahora nuestra ensalada Set
es así:
Set(3) {"?", "?", "?"}
- Usa el método
clear()
para quitar todos los elementos de unSet
:
setEnsalada.clear();
Cómo iterar sobre un Set en JavaScript
Set
tiene un método llamado values()
el cual regresa un SetIterator
para obtener todos sus valores:
// Crea un Set
const nrosCasas = new Set([360, 567, 101]);
// Obtener el SetIterator usando el método `values()`
console.log(nrosCasas.values());
Salida:
SetIterator {360, 567, 101}
Podemos usar un bucle forEach
o for-of
para recuperar los valores.
Interesantemente, JavaScript intenta hacer a Set
compatible con Map
. Por eso encontramos dos de los mismos métodos como en Map
, keys()
y entries()
.
Ya que Set
no tiene claves, el método keys()
regresa un SetIterator
para recuperar sus valores:
console.log(nrosCasas.keys());
// Salida
// console.log(nrosCasas.keys());
Con Map
, el método entries()
regresa un iterador para recuperar pares de clave-valor. De nuevo, no hay claves en un Set
, así que entries()
regresa un SetIterator
para recuperar los pares de valor-valor:
console.log(nrosCasas.entries());
// Salida
// SetIterator {360 => 360, 567 => 567, 101 => 101}
Cómo enumerar sobre un Set en JavaScript
Podemos enumerar sobre un Set usando los bucles forEach
y for-of
:
// con forEach
nrosCasas.forEach((valor) => {
console.log(valor);
});
// con for-of
for(const valor of nrosCasas) {
console.log(valor);
}
La salida de ambos es:
360
567
101
Sets y arreglos en JavaScript
Un arreglo, como un Set
, te permite agregar y quitar elementos. Pero Set
es muy diferente, y no está destinado para reemplazar los arreglos.
La mayor diferencia entre un arreglo y un Set
es que los arreglos te permiten tener elementos duplicados. También, algunas de las operaciones de Set
como delete()
son más rápidos que las operaciones del arreglo como shift()
o splice()
.
Piensa de Set
como una extensión de un arreglo regular, solo que con más músculos. La estructura de datos Set
no es un reemplazo del array
. Ambos pueden resolver problemas interesantes.
Cómo convertir un Set en un arreglo en JavaScript
Convertir un Set
en un arreglo es simple:
const arr = [...nrosCasas];
console.log(arr);
Valores únicos de un arreglo usando el Set en JavaScript
Crear un Set
es una forma realmente sencilla para quitar valores duplicados de un arreglo:
// Crea un arreglo frutasMezcladas con unas pocas frutas duplicadas
const frutasMezcladas = ['?', '?', '?', '?', '?', '?', '?'];
// Pasa el arreglo para crear un conjunto de frutas únicas
const setFrutasMezcladas = new Set(frutasMezcladas);
console.log(setFrutasMezcladas);
Salida:
Set(4) {"?", "?", "?", "?"}
Set y Object en JavaScript
Un Set
puede tener elementos de cualquier tipo, inclusive objetos:
// Crea un objeto de persona
const persona = {
'nombre': 'Alex',
'edad': 32
};
// Crea un conjunto y le agrega el objeto
const setP = new Set();
setP.add(persona);
console.log(setP);
Salida:
No hay sorpresa aquí – el Set
contiene un elemento que es un objeto.
Cambiemos una propiedad del objeto y agreguémosle al set de nuevo:
// Cambiar el nombre de la persona
persona.nombre = 'Bob';
// Agregar el objeto de persona al set otra vez
setP.add(persona);
console.log(setP);
¿Qué salida piensas que será? ¿Dos objetos persona
o solo uno?
Aquí está la salida:
Set
es una colección de elementos únicos. Cambiando la propiedad del objeto, no hemos cambiado el objeto mismo. Sin embargo, Set
no permitirá duplicar elementos.
Set
es una estructura de datos genial para usar en adición a los arreglos de JavaScript. Aunque no tiene una gran ventaja sobre los arreglos regulares.
Usa Set
cuando necesites mantener un conjunto de datos distintivo para ejecutar operaciones de Set como union
, intersection
, difference
, y así sucesivamente.
En Resumen
Aquí hay un repositorio de GitHub para encontrar todo el código fuente usado en este artículo. Si lo encontraste útil, por favor muestra tu apoyo dándole una estrellita: https://github.com/atapas/js-collections-map-set.
Te podría gustar también algunos de mis otros artículos:
- Mis Tips y Trucos Favoritos de JavaScript
- La igualdad y similitud de JavaScript con ==, === y Object.is()
Si este artículo te fue útil, por favor compártelo así otros lo pueden leer también. Puedes etiquetarme @ en Twitter (@tapasadhikary) con comentarios, o no dudes en seguirme.