Signatur
Beschreibung
getOrInsertComputed() fasst das bekannte Muster „nachsehen, ob ein Schlüssel existiert, sonst einen Standardwert anlegen“ in einem Aufruf zusammen. Existiert key bereits in der Map, gibt die Methode den gespeicherten Wert unverändert zurück. Existiert er nicht, ruft sie callbackFn mit dem Schlüssel auf, speichert den Rückgabewert unter diesem Schlüssel und gibt ihn zurück.
Im Unterschied zu Map.prototype.getOrInsert(key, value) wird der Standardwert erst bei Bedarf berechnet. Das ist wichtig, wenn das Erzeugen teuer ist (z. B. eine aufwendige Berechnung oder ein neues Objekt), wenn es Nebenwirkungen hat oder wenn der Wert vom Schlüssel abhängt. Typische Einsatzfälle sind Caches und Memoisierung, das Gruppieren von Daten in Arrays oder Sets und Registries, die Einträge beim ersten Zugriff anlegen.
Gegenüber dem klassischen Muster if (!map.has(k)) map.set(k, init()); return map.get(k); ist die Methode kürzer und durchsucht die Map nicht mehrfach. Außerdem funktioniert sie auch dann richtig, wenn der gespeicherte Wert undefined ist. Das Muster map.get(k) ?? … scheitert dagegen genau daran.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $key Pflicht | any | Der gesuchte Schlüssel. Wie bei allen Map-Methoden wird er nach SameValueZero verglichen; -0 wird als +0 gespeichert. |
|
| $callbackFn Pflicht | (key: any) => any | Funktion, die nur bei fehlendem Schlüssel aufgerufen wird. Sie erhält key als einziges Argument. Ihr Rückgabewert wird eingefügt und zurückgegeben. |
Rückgabewert
key oder, falls der Schlüssel fehlte, den neu berechneten und eingefügten Rückgabewert von callbackFn.Beispiele
Daten nach Kategorie gruppieren
const produkte = [
{ name: 'Apfel', kategorie: 'Obst' },
{ name: 'Karotte', kategorie: 'Gemüse' },
{ name: 'Birne', kategorie: 'Obst' }
];
const gruppen = new Map();
for (const p of produkte) {
// Das Array wird nur beim ersten Auftreten der Kategorie angelegt
gruppen.getOrInsertComputed(p.kategorie, () => []).push(p.name);
}
console.log(gruppen);
Memoisierung einer teuren Berechnung
const cache = new Map();
const fib = (n) => cache.getOrInsertComputed(n, (k) => {
console.log(`berechne ${k}`);
return k < 2 ? k : fib(k - 1) + fib(k - 2);
});
console.log(fib(5));
console.log(fib(5)); // kommt jetzt direkt aus dem Cache
Vergleich mit getOrInsert: Wert nur bei Bedarf berechnen
const sitzungen = new Map([['anna', { id: 1 }]]);
const erstelleSitzung = (user) => {
console.log(`Neue Sitzung für ${user}`);
return { id: Math.floor(Math.random() * 1000) };
};
// Vorhandener Schlüssel: der Callback wird NICHT aufgerufen
console.log(sitzungen.getOrInsertComputed('anna', erstelleSitzung));
// Fehlender Schlüssel: der Callback läuft genau einmal
const s = sitzungen.getOrInsertComputed('ben', erstelleSitzung);
console.log(sitzungen.has('ben'), sitzungen.get('ben') === s);
// Wichtig · Fallstricke
- Kompatibilität: Die Methode ist neu (TC39-Proposal „Upsert“) und wird noch nicht in allen Browsern und Node.js-Versionen unterstützt. Deshalb vorher prüfen, etwa mit
typeof Map.prototype.getOrInsertComputed === 'function', oder ein Polyfill wiecore-jseinsetzen. - Ist
callbackFnkeine Funktion, wird einTypeErrorausgelöst. Das passiert auch dann, wenn der Schlüssel bereits existiert. - Löst
callbackFneine Ausnahme aus, wird nichts eingefügt, und die Ausnahme wird weitergereicht. - Verändert der Callback die Map selbst, etwa weil er denselben Schlüssel setzt, wird dieser Eintrag anschließend mit dem Rückgabewert des Callbacks überschrieben. Rekursive Aufrufe wie im Memoisierungsbeispiel funktionieren, sollten aber mit Bedacht eingesetzt werden.
- Ein Callback, der
undefinedzurückgibt, fügt trotzdem einen Eintrag ein.has(key)liefert danach alsotrue. - Für einfache, günstige Standardwerte wie
0reichtgetOrInsert(). Für neue Objekte oder Arrays istgetOrInsertComputed()sinnvoller, weil nicht bei jedem Aufruf unnötig ein Objekt erzeugt wird. - Eine gleichnamige Methode gibt es auch auf
WeakMap. Dort muss der Schlüssel ein Objekt oder ein nicht registriertes Symbol sein.