![]() |
In JavaScript, spesso lavoriamo con strutture dati come Map o Set per associare chiavi a valori o memorizzare collezioni di elementi. Tuttavia, quando si ha la necessità di associare dati a oggetti senza influenzare il ciclo di vita di quegli oggetti, WeakMap diventa uno strumento potente e insostituibile.
✅ Cos’è un WeakMap?
Un WeakMap è una collezione di coppie chiave/valore in cui:
- Le chiavi devono essere oggetti (non primitive).
- I riferimenti alle chiavi sono deboli, ovvero non impediscono il garbage collection.
- Non è iterabile: non possiamo usare
for...of,.keys()o.entries()per esplorarne i contenuti.
Queste caratteristiche rendono WeakMap particolarmente utile in scenari dove si vuole collegare dati a oggetti in modo non intrusivo e senza rischio di memory leak.
🔍 Perché usare WeakMap?
- Gestione della memoria: Le chiavi deboli permettono la rimozione automatica degli oggetti non più usati.
- Integrazione trasparente: Permette di associare dati ad oggetti senza modificarli.
- Sicurezza e incapsulamento: Le chiavi non sono accessibili dall’esterno; nessuno può enumerarle.
📊 WeakMap vs Map: Confronto Diretto
| Caratteristica | Map |
WeakMap |
|---|---|---|
| Chiavi | Oggetti, primitive | Solo oggetti |
| Garbage collection | Chiavi mantenute in memoria | Chiavi debolmente referenziate |
| Iterabilità | Sì, con .keys(), .forEach(), ecc. |
No |
| Visibilità | Accessibile con .size, .entries() |
Inaccessibile |
| Utilizzo tipico | Collezioni generiche | Dati privati, cache temporanee |
📌 Punti chiave
-
Maptrattiene le chiavi in memoria, quindi può causare memory leak se non gestita bene. -
WeakMapnon trattiene le chiavi, quindi è ideale per memorizzare dati associati ad oggetti in modo temporaneo o privato. -
Questo comportamento è cruciale per:
-
cache automatiche
-
gestione di risorse dinamiche (es. DOM)
-
dati privati di oggetti che possono essere distrutti in modo naturale
-
🧹 Esempio concreto: WeakMap e Garbage Collection
🎯 Obiettivo
Associare dati temporanei a elementi DOM senza causare memory leak.
const elementData = new WeakMap();
function attachMetadata(element) {
const data = {
clickedAt: Date.now(),
temporarySetting: Math.random()
};
elementData.set(element, data);
}
function handleClick(event) {
const element = event.target;
attachMetadata(element);
console.log('Metadata stored:', elementData.get(element));
}
let button = document.createElement('button');
button.textContent = 'Click me';
document.body.appendChild(button);
button.addEventListener('click', handleClick);
setTimeout(() => {
document.body.removeChild(button);
button = null; // Remove last reference
// Now both the DOM element and its metadata can be garbage collected
}, 5000);
Con una Map, l’elemento e i dati associati sarebbero rimasti in memoria.
Con WeakMap, appena l’elemento non ha più riferimenti attivi, tutto viene pulito automaticamente dal garbage collector.
🛑 Limitazioni di WeakMap
❌ 1. Non è iterabile: non puoi accedere a tutte le chiavi o valori
const wm = new WeakMap();
const obj = {};
wm.set(obj, 'data');
for (const [key, value] of wm) {
console.log(key, value); // ❌ TypeError: wm is not iterable
}
❌ 2. Le chiavi devono essere oggetti: non puoi usare stringhe, numeri, ecc.
const wm = new WeakMap();
wm.set('user', 'data'); // ❌ TypeError: Invalid value used as weak map key
❌ 3. Nessuna proprietà .size
const wm = new WeakMap();
const a = {}, b = {};
wm.set(a, 1);
wm.set(b, 2);
console.log(wm.size); // ❌ undefined
❌ 4. Nessuna visibilità sul contenuto
const wm = new WeakMap();
const obj = {};
wm.set(obj, 'secret');
console.log(wm.has(obj)); // ✔️ true
console.log([...wm.keys()]); // ❌ TypeError: wm.keys is not a function
🧪 Esempi pratici di utilizzo di una WeakMap
📌 1. Associare metadati a oggetti
user, ma vengono memorizzati in una struttura separata e invisibile al di fuori delle funzioni definite.const metaData = new WeakMap();
function setMetadata(obj, data) {
metaData.set(obj, data);
}
function getMetadata(obj) {
return metaData.get(obj);
}
const user = { name: 'Alice' };
setMetadata(user, { role: 'admin' });
console.log(getMetadata(user)); // { role: 'admin' }
📌 2. Proprietà private in una classe
WeakMap viene utilizzato per tenere i dati count fuori dalla portata diretta del codice utente, emulando la visibilità privata.const privateProps = new WeakMap();
class Counter {
constructor() {
privateProps.set(this, { count: 0 });
}
increment() {
const data = privateProps.get(this);
data.count++;
}
getCount() {
return privateProps.get(this).count;
}
}
const counter = new Counter();
counter.increment();
counter.increment();
console.log(counter.getCount()); // 2
console.log(counter.count); // undefined
📌 3. Cache automatica per funzioni
WeakMap, la cache associata a data verrà rimosso automaticamente quando data non sarà più utilizzato, evitando accumuli di memoria non voluti.const cache = new WeakMap();
function process(obj) {
if (cache.has(obj)) {
return cache.get(obj);
}
const result = computeHeavyTask(obj);
cache.set(obj, result);
return result;
}
function computeHeavyTask(obj) {
return obj.value * 1000;
}
const data = { value: 5 };
console.log(process(data)); // 5000
console.log(process(data)); // 5000, cached
🎯 Conclusione
WeakMap è un potente strumento per:
- Associare dati privati a oggetti senza modificarli
- Gestire cache in modo automatico e sicuro
- Prevenire memory leak in scenari dinamici (DOM, componenti)
Non sostituisce Map, ma si rivela essenziale in contesti dove la gestione della memoria e la privacy dei dati sono fondamentali.
Follow me #techelopment
Official site: www.techelopment.it
facebook: Techelopment
instagram: @techelopment
X: techelopment
Bluesky: @techelopment
whatsapp: Techelopment
youtube: @techelopment
