Map y Set
Colecciones de datos modernas
JavaScript Moderno: Map, Set y las nuevas estructuras de datos
Las estructuras de datos Map y Set, introducidas con ES6, ofrecen nuevas y potentes formas de gestionar colecciones de datos en JavaScript.
Map
Map es una colección de pares clave-valor en la que las claves pueden ser de cualquier tipo.
Creación y manipulación básica
// Création d'une Map
const utilisateurs = new Map();
// Ajout d'éléments
utilisateurs.set('alice', { nom: 'Alice', age: 25 });
utilisateurs.set('bob', { nom: 'Bob', age: 30 });
// Récupération de valeurs
console.log(utilisateurs.get('alice')); // { nom: 'Alice', age: 25 }
// Vérification d'existence
console.log(utilisateurs.has('bob')); // true
// Suppression d'éléments
utilisateurs.delete('bob');
// Taille de la Map
console.log(utilisateurs.size); // 1
// Vider la Map
utilisateurs.clear();
Inicialización con un array
const contacts = new Map([
['alice', '0123456789'],
['bob', '9876543210']
]);
// Itération sur les entrées
for (const [nom, telephone] of contacts) {
console.log(`${nom}: ${telephone}`);
}
Métodos de iteración
const scores = new Map([
['Alice', 95],
['Bob', 80],
['Charlie', 85]
]);
// Itération sur les clés
for (const nom of scores.keys()) {
console.log(nom);
}
// Itération sur les valeurs
for (const score of scores.values()) {
console.log(score);
}
// Itération sur les entrées
scores.forEach((score, nom) => {
console.log(`${nom}: ${score}`);
});
Casos de uso avanzados
// Utilisation d'objets comme clés
const objetA = { id: 1 };
const objetB = { id: 2 };
const donnees = new Map();
donnees.set(objetA, 'Données pour A');
donnees.set(objetB, 'Données pour B');
console.log(donnees.get(objetA)); // "Données pour A"
// Conversion Map vers Object
const mapVersObjet = Object.fromEntries(scores);
// Conversion Object vers Map
const objet = { a: 1, b: 2 };
const objetVersMap = new Map(Object.entries(objet));
Set
Set es una colección de valores únicos de cualquier tipo.
Creación y manipulación básica
// Création d'un Set
const nombres = new Set();
// Ajout d'éléments
nombres.add(1);
nombres.add(2);
nombres.add(2); // Ignoré car déjà présent
console.log(nombres.size); // 2
// Vérification d'existence
console.log(nombres.has(1)); // true
// Suppression d'éléments
nombres.delete(1);
// Vider le Set
nombres.clear();
Inicialización con un array
const fruits = new Set(['pomme', 'banane', 'pomme', 'orange']);
console.log(fruits.size); // 3 (pomme n'est compté qu'une fois)
// Conversion Set vers Array
const fruitsUniques = [...fruits];
Operaciones sobre conjuntos
function intersection(setA, setB) {
return new Set([...setA].filter(x => setB.has(x)));
}
function union(setA, setB) {
return new Set([...setA, ...setB]);
}
function difference(setA, setB) {
return new Set([...setA].filter(x => !setB.has(x)));
}
// Exemple d'utilisation
const setA = new Set([1, 2, 3, 4]);
const setB = new Set([3, 4, 5, 6]);
console.log(intersection(setA, setB)); // Set(2) {3, 4}
console.log(union(setA, setB)); // Set(6) {1, 2, 3, 4, 5, 6}
console.log(difference(setA, setB)); // Set(2) {1, 2}
WeakMap y WeakSet
Estas versiones «débiles» permiten la recolección automática de los elementos que ya no están referenciados.
WeakMap
// Création d'une WeakMap
const cache = new WeakMap();
let objet = { id: 1 };
cache.set(objet, 'données associées');
// Si objet est mis à null, les données seront nettoyées
objet = null;
WeakSet
const abonnes = new WeakSet();
let utilisateur = { nom: 'Alice' };
abonnes.add(utilisateur);
console.log(abonnes.has(utilisateur)); // true
// Si utilisateur est mis à null, il sera automatiquement retiré
utilisateur = null;
Patrones y casos de uso prácticos
Caché con Map
class Cache {
constructor(ttl = 3600000) { // TTL par défaut : 1 heure
this.cache = new Map();
this.ttl = ttl;
}
set(key, value) {
this.cache.set(key, {
value,
timestamp: Date.now()
});
}
get(key) {
const item = this.cache.get(key);
if (!item) return null;
if (Date.now() - item.timestamp > this.ttl) {
this.cache.delete(key);
return null;
}
return item.value;
}
clear() {
this.cache.clear();
}
}
// Utilisation
const cache = new Cache(5000); // TTL de 5 secondes
cache.set('utilisateur', { id: 1, nom: 'Alice' });
Gestor de eventos con Set
class EventEmitter {
constructor() {
this.listeners = new Map();
}
on(event, callback) {
if (!this.listeners.has(event)) {
this.listeners.set(event, new Set());
}
this.listeners.get(event).add(callback);
}
off(event, callback) {
if (this.listeners.has(event)) {
this.listeners.get(event).delete(callback);
}
}
emit(event, data) {
if (this.listeners.has(event)) {
for (const callback of this.listeners.get(event)) {
callback(data);
}
}
}
}
// Utilisation
const emitter = new EventEmitter();
const handler = data => console.log('Données reçues:', data);
emitter.on('data', handler);
emitter.emit('data', { message: 'Hello' });
Gestión del estado con Map
class Store {
constructor() {
this.state = new Map();
this.subscribers = new Map();
}
setState(key, value) {
this.state.set(key, value);
if (this.subscribers.has(key)) {
this.subscribers.get(key).forEach(callback =>
callback(value)
);
}
}
getState(key) {
return this.state.get(key);
}
subscribe(key, callback) {
if (!this.subscribers.has(key)) {
this.subscribers.set(key, new Set());
}
this.subscribers.get(key).add(callback);
return () => this.subscribers.get(key).delete(callback);
}
}
// Utilisation
const store = new Store();
const unsubscribe = store.subscribe('compteur', value =>
console.log('Nouveau compteur:', value)
);
store.setState('compteur', 1); // Affiche "Nouveau compteur: 1"
Ejercicios prácticos
- Gestor de tareas únicas
class GestionnaireTaches {
constructor() {
this.taches = new Set();
}
ajouterTache(tache) {
if (this.taches.has(tache)) {
return false;
}
this.taches.add(tache);
return true;
}
supprimerTache(tache) {
return this.taches.delete(tache);
}
getTaches() {
return [...this.taches];
}
}
// Utilisation
const gestionnaire = new GestionnaireTaches();
gestionnaire.ajouterTache('Apprendre JavaScript');
gestionnaire.ajouterTache('Apprendre JavaScript'); // Retourne false
console.log(gestionnaire.getTaches()); // ["Apprendre JavaScript"]
- Sistema de caché con expiración
class CacheAvecExpiration {
constructor() {
this.cache = new Map();
}
set(key, value, ttl) {
const expiration = Date.now() + ttl;
this.cache.set(key, { value, expiration });
}
get(key) {
const item = this.cache.get(key);
if (!item) return null;
if (Date.now() > item.expiration) {
this.cache.delete(key);
return null;
}
return item.value;
}
nettoyer() {
const maintenant = Date.now();
for (const [key, item] of this.cache) {
if (maintenant > item.expiration) {
this.cache.delete(key);
}
}
}
}
// Utilisation
const cache = new CacheAvecExpiration();
cache.set('api-data', { results: [] }, 5000); // Expire après 5 secondes
Conclusión
Map y Set son estructuras de datos esenciales en JavaScript moderno:
- Map ofrece una alternativa más flexible a los objetos para las colecciones clave-valor
- Set simplifica la gestión de colecciones de valores únicos
- WeakMap y WeakSet son útiles para la gestión de la memoria
- Estas estructuras facilitan la implementación de patrones habituales como la caché y la gestión de eventos
En el próximo tutorial pondremos en práctica todos estos conocimientos en un proyecto completo de aplicación de notas.
¿Necesitas repasar los módulos ES? Consulta nuestro tutorial anterior sobre los módulos.
Comentarios
Los comentarios funcionan con GitHub Discussions
Inicia sesión con GitHub para participar en la discusión