Signatur
Beschreibung
Mit getOrInsertComputed() liest du einen Wert aus einer WeakMap und legst ihn in einem Schritt an, falls er noch fehlt. Ist key schon vorhanden, gibst du den gespeicherten Wert zurück, und die Callback-Funktion wird nicht aufgerufen. Fehlt der Schlüssel, wird callbackFn(key) aufgerufen. Das Ergebnis wird unter key gespeichert und zurückgegeben.
Die Methode ersetzt das bekannte Muster if (!wm.has(k)) wm.set(k, berechne()); return wm.get(k);. Sie ist kürzer und schlägt nur einmal nach, wenn der Schlüssel schon existiert. Typische Einsatzfälle sind Caches und Memoisierung pro Objekt und das Speichern privater Metadaten zu DOM-Elementen oder Klasseninstanzen. Dabei soll der Speicher automatisch freigegeben werden, sobald das Schlüsselobjekt nicht mehr erreichbar ist.
Im Unterschied zu getOrInsert() wird der Standardwert nur bei Bedarf berechnet. Das lohnt sich, wenn die Berechnung teuer ist oder Nebenwirkungen hat, zum Beispiel ein neues Objekt anlegen, rechnen oder messen.
Wie bei allen WeakMap-Operationen muss key ein Objekt oder ein nicht registriertes Symbol sein. Primitive Werte sind als Schlüssel nicht erlaubt.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $key Pflicht | object | symbol | Der Schlüssel, zu dem der Wert gesucht wird. Erlaubt sind nur Objekte und Symbole, die nicht mit Symbol.for() registriert wurden. |
|
| $callbackFn Pflicht | (key: object | symbol) => any | Funktion, die den Wert berechnet, falls key fehlt. Sie bekommt key als einziges Argument. Ihr Rückgabewert wird gespeichert und zurückgegeben. |
Rückgabewert
key. Fehlt der Schlüssel, den gerade von callbackFn berechneten und eingefügten Wert.Beispiele
Grundprinzip: Wert nur bei Bedarf berechnen
const wm = new WeakMap();
const user = { name: 'Ada' };
const first = wm.getOrInsertComputed(user, (key) => {
console.log('berechne für', key.name);
return { visits: 0 };
});
// Zweiter Aufruf: Callback läuft nicht mehr
const second = wm.getOrInsertComputed(user, () => {
console.log('wird nie ausgegeben');
return { visits: 99 };
});
console.log(first === second, second.visits);
Teure Berechnung pro Objekt zwischenspeichern
const statsCache = new WeakMap();
const getStats = (numbers) =>
statsCache.getOrInsertComputed(numbers, (arr) => {
const sum = arr.reduce((a, b) => a + b, 0);
return { sum, avg: sum / arr.length, max: Math.max(...arr) };
});
const messwerte = [3, 8, 1, 12, 6];
console.log(getStats(messwerte));
console.log(getStats(messwerte) === getStats(messwerte)); // aus dem Cache
Metadaten zu DOM-Elementen ohne Speicherleck
const clickCounts = new WeakMap();
document.addEventListener('click', (event) => {
const el = event.target;
const meta = clickCounts.getOrInsertComputed(el, () => ({
count: 0,
firstClick: Date.now(),
}));
meta.count++;
console.log(`${el.tagName}: ${meta.count} Klick(s)`);
});
// Wird ein Element aus dem DOM entfernt und ist sonst nicht mehr
// erreichbar, kann der Garbage Collector auch den Eintrag freigeben.
Vorher/nachher: Ersatz für has/get/set
const listeners = new WeakMap();
const target = {};
// Klassisch:
// if (!listeners.has(target)) listeners.set(target, new Set());
// listeners.get(target).add(handler);
// Mit getOrInsertComputed:
const handler = () => console.log('Event!');
listeners.getOrInsertComputed(target, () => new Set()).add(handler);
listeners.getOrInsertComputed(target, () => new Set()).add(handler);
console.log(listeners.get(target).size);
// Wichtig · Fallstricke
- Sehr neue API: Die Methode stammt aus dem TC39-Proposal „Upsert“ und wird erst von aktuellen Browserversionen und neuen Laufzeitumgebungen unterstützt. Prüfe die Unterstützung vor dem Einsatz, zum Beispiel mit
typeof WeakMap.prototype.getOrInsertComputed === 'function'. Alternativ nutzt du ein Polyfill wie core-js. - Ungültige Schlüssel: Ist
keyein primitiver Wert oder ein mitSymbol.for()registriertes Symbol, wird einTypeErrorausgelöst. Das geschieht noch bevorcallbackFnaufgerufen wird. EinTypeErrorfolgt auch, wenncallbackFnkeine Funktion ist. - Ausnahmen im Callback: Wirft
callbackFneinen Fehler, wird nichts eingefügt, und der Fehler wird weitergereicht. - Änderungen im Callback: Setzt der Callback selbst einen Wert für denselben
key, wird dieser Wert danach vom Rückgabewert des Callbacks überschrieben. Solche Nebenwirkungen solltest du vermeiden. - Kein Unterschied zwischen
undefinedund fehlend: Gibt der Callbackundefinedzurück, wirdundefinedgespeichert. Bei späteren Aufrufen gilt der Schlüssel dann als vorhanden. - Ist der Standardwert billig und hat keine Nebenwirkungen, genügt
getOrInsert(key, value).