Map e Set
Coleções de Dados Modernas
JavaScript Moderno: Map, Set e as novas estruturas de dados
As estruturas de dados Map e Set, introduzidas com o ES6, oferecem novas e poderosas formas de gerenciar coleções de dados em JavaScript.
Map
Map é uma coleção de pares chave-valor em que as chaves podem ser de qualquer tipo.
Criação e manipulação 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();
Inicialização com um 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 iteração
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 avançados
// 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 é uma coleção de valores únicos de qualquer tipo.
Criação e manipulação 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();
Inicialização com um 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];
Operações com 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 e WeakSet
Essas versões “fracas” permitem a coleta automática de elementos não 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;
Padrões e casos de uso práticos
Cache com 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' });
Gerenciador de eventos com 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' });
Gerenciamento de estado com 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"
Exercícios práticos
- Gerenciador de tarefas ú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 cache com expiração
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
Conclusão
Map e Set são estruturas de dados essenciais no JavaScript moderno:
- Map oferece uma alternativa mais flexível aos objetos para coleções chave-valor
- Set simplifica o gerenciamento de coleções de valores únicos
- WeakMap e WeakSet são úteis para o gerenciamento de memória
- Essas estruturas facilitam a implementação de padrões comuns, como cache e gerenciamento de eventos
No próximo tutorial, vamos colocar em prática todo esse conhecimento em um projeto completo de aplicativo de notas.
Precisa revisar os módulos ES? Consulte nosso tutorial anterior sobre módulos.
Comentários
Os comentários são alimentados pelo GitHub Discussions
Conecte-se com o GitHub para participar da discussão