Estamos tan acostumbrados a ir tirando con arrays y objetos, que a veces nos olvidamos de que tenemos otras estructuras disponibles que en algunos casos nos pueden ser de mucha utilidad. Vamos a ver en qué consisten los maps y los sets.
Usando Map en JavaScript
No confundir con Array.prototype.map(). No, estamos hablando de la estructura Map, que es una colección de elementos con clave y valor, como los objetos. La diferencia con éstos, es que en un mapa podemos almacenar cualquier tipo de dato en la clave.
En un objeto las claves siempre serán una cadena de texto o un símbolo JavaScript, pero en un mapa podemos usar cualquier tipo de dato en la clave. Mira:
const miMapa = new Map() miMapa.set({ nombre: "Pol" }, "información") console.log(miMapa) // {nombre: "Pol"}: "información"
Hemos guardado un objeto como clave.
Además, en un mapa el orden de los elementos a medida que vamos añadiendo se mantiene, a diferencia con los objetos. Ten en cuenta también que los mapas no se pueden reordenar.
Si conocemos la información que vamos a almacenar en la coleción y no hay ninguna clave que sea de otro tipo que texto o símbolo, entonces un objeto puede ser la solución. Ahora bien, si las claves de la colección no se conocen hasta la ejecución del código, entonces un mapa será la solución ideal para evitar posibles errores.
Otro caso de uso es cuando tenemos que almacenar una cantidad muy grande de información en la colección. Habitualmente un mapa rendirá mejor que un objeto. Tienen un mejor rendimiento en la adición y eliminación de elementos, así que si esa es una tarea muy habitual en la colección, además de ser bastante grande, usa mejor un mapa.
Si tu intención es serializar la colección a formato JSON, entonces usa objetos, ya que por defecto no hay ningún serializador nativo para mapas, aunque podrías llegar a hacer uno personalizado.
Cómo usar mapas
Así podemos crear un mapa, además de añadir, eliminar y actualizar elementos:
// creamos un nuevo mapa const miCompra = new Map() // añadimos elementos a la lista de la compra (elemento, precio) miCompra.set("Café", 5) miCompra.set("Queso", 2) miCompra.set("Salmón", 7) // actualizamos el precio del café miCompra.set("Café", 6) // eliminamos un elemento miCompra.delete("Café") // eliminamos todos los elementos miCompra.clear()
Si queremos crear un elemento nuevo usamos set, pero si queremos recoger uno de los elementos podemos usar get:
const miCompra = new Map() miCompra.set("Café", 5) miCompra.set("Queso", 2) miCompra.set("Salmón", 7) // obtenemos el valor de un elemento const item = miCompra.get("Queso") console.log(item) // 2
Para iterar un mapa, tenemos los métodos keys(), values() y entries() que devuelven un iterador:
const miCompra = new Map() miCompra.set("Café", 5) miCompra.set("Queso", 2) miCompra.set("Salmón", 7) // iteramos las claves del mapa for (const item of miCompra.keys()) { console.log(item) } // Café, Queso, Salmón // iteramos los valores del mapa for (const precio of miCompra.values()) { console.log(precio) } // 5, 2, 7 // iteramos cada elemento del mapa con su clave y valor for (const elemento of miCompra.entries()) { console.log(elemento) } // ["Café", 5], ["Queso", 2], ["Salmón", 7]
Y finalmente, también podemos comprobar el tamaño del mapa y saber si hay cierto elemento con size() y has() respectivamente:
const miCompra = new Map() miCompra.set("Café", 5) miCompra.set("Queso", 2) miCompra.set("Salmón", 7) // ¿tenemos salmón? console.log(miCompra.has("Salmón")) // true // ¿tenemos ternera? console.log(miCompra.has("Ternera")) // false // total elementos en la lista de la compra console.log(miCompra.size) // 3
Como puedes ver, tenemos algunas cosas en los mapas que en los objetos no. Resumiendo, un mapa es una buena opción cuando:
- Tenemos muchos elementos
- Queremos preservar un orden
- Necesitaremos contar la cantidad de elementos habitualmente
- No conocemos el tipo de dato que habrá en las claves
- Sabemos que vamos a guardar datos que no son ni texto ni símbolos en las claves
Usando Set en JavaScript
Un set es una colección de elementos sin claves, es decir, son parecidos a un array. La diferencia, es que en los sets no hay elementos repetidos. ¿Cuántas veces has alimentado un array de elementos para posteriormente eliminar sus repetidos? Sí, a todos nos ha pasado.
Cuando se añade un nuevo elemento a un set, automáticamente se revisa si ese elemento ya existe antes de proceder. Al igual que con los mapas, mantienen el orden de los elementos que se van añadiendo y no es posible reordenarlos.
Cómo usar sets
Así creamos, añadimos y eliminamos elementos:
// creamos un nuevo set const miLista = new Set() // añadimos tres valores miLista.add(1) miLista.add(2) miLista.add(3) // esto no añade ningún valor nuevo miLista.add(1) // 1 ya existe // eliminamos un elemento miLista.delete(2)
Ojo no caigas en la trampa de los repetidos con los objetos. Mira:
const miLista = new Set() const item1 = { instrumento: "guitarra" } const item2 = { instrumento: "bajo" } const item3 = { instrumento: "batería" } miLista.add(item1) miLista.add(item2) miLista.add(item3) // esto no añade ningún elemento nuevo miLista.add(item3) console.log(miLista.size) // 3 // en cambio, esto sí miLista.add({ instrumento: "batería" }) console.log(miLista.size) // 4
Esto sucede porque en JavaScript, las variables guardan la referencia a los objetos, no su contenido. Cuando estamos añadiendo el cuarto elemento, realmente no se trata del mismo objeto, es otro diferente con la misma estructura.
Podemos iterar un set con el método values():
const miLista = new Set() miLista.add(1) miLista.add(2) miLista.add(3) for (const elemento of miLista.values()) { console.log(elemento) } // 1, 2, 3
Además, con el método has() podemos comprobar si un elemento existe o no en el set:
const miLista = new Set() miLista.add(1) miLista.add(2) miLista.add(3) console.log(miLista.has(4)) // false console.log(miLista.has(1)) // true
Podemos convertir un set a array y viceversa de forma sencilla:
const miLista = new Set() miLista.add(1) miLista.add(2) miLista.add(3) // convertimos el set en un array const nuevaLista = [...miLista.values()] console.log(Array.isArray(nuevaLista)) // true // convertimos un array en un set const conRepetidos = [1, 2, 3, 3] const sinRepetidos = new Set(conRepetidos) console.log(sinRepetidos) // [1, 2, 3]
Esto nos permitirá hacer cambios según nos interese, por ejemplo, para ordenar el set transformándolo primero en un array y luego volviendo a crear el set después de ordenarlo.
En resumen, el set te puede ser útil si:
- Quieres evitar duplicados
- No te importa el orden de los elementos
- no vas a necesitar los métodos map(), filter() y reduce()
Como los sets no tienen disponibles los métodos map(), filter() y reduce(), quizás te sea más cómodo trabajar con arrays y hacer la transformación a sets en momentos concretos para eliminar duplicados.
Conclusiones
Los mapas y los sets tienen ciertos casos de uso que nos pueden ser muy útiles y facilitarnos el trabajo. Estas dos estructuras fueron introducidas con ES6 y desde entonces nos han ayudado a mejorar la interacción con los objetos y arrays clásicos, pudiendo superar algunas de sus limitaciones.