Start · Sprachen · JavaScript · Referenz · Map.prototype.getOrInsert()

Map.prototype.getOrInsert()

Methode

Gibt den Wert zu <code>key</code> zurück. Fehlt der Schlüssel, wird <code>defaultValue</code> eingefügt und zurückgegeben.

seit JavaScript TC39-Proposal „Upsert“ (Stage 3); noch nicht Basel Kategorie: method-property

Signatur

Map.prototype.getOrInsert(key, defaultValue)

Beschreibung

Die Methode getOrInsert() fasst ein sehr häufiges Muster in einem Aufruf zusammen: „Hole den Wert zu einem Schlüssel; gibt es noch keinen, lege einen Standardwert an.“ Existiert key bereits in der Map, wird der vorhandene Wert unverändert zurückgegeben. Andernfalls wird defaultValue unter key gespeichert und dann zurückgegeben.

Bisher schrieb man dafür meist if (!map.has(key)) map.set(key, wert); return map.get(key);. Das braucht bis zu drei Hash-Zugriffe und ist fehleranfällig. getOrInsert() ist kürzer, sagt klarer, was gemeint ist, und kann von der Engine effizienter umgesetzt werden. Typische Einsätze sind Gruppierungen (Schlüssel → Array), Zähler (Schlüssel → Zahl) und verschachtelte Maps.

Wichtig: defaultValue wird immer ausgewertet, bevor die Methode aufgerufen wird, auch wenn der Schlüssel schon existiert. Bei teuren oder seiteneffektbehafteten Standardwerten nimmt man deshalb Map.prototype.getOrInsertComputed(). Dort wird der Wert über eine Callback-Funktion erst bei Bedarf berechnet.

Parameter

Name Typ Default Beschreibung
$key Pflicht any Der Schlüssel, der gesucht wird. Der Vergleich läuft wie bei Map über SameValueZero (NaN ist gleich NaN, -0 wird zu +0).
$defaultValue Pflicht any Der Wert, der eingefügt und zurückgegeben wird, falls key noch nicht in der Map steht. Er wird bei jedem Aufruf ausgewertet.

Rückgabewert

Typ
any
Beschreibung
Der vorhandene Wert zu key. Fehlte der Schlüssel, ist es der gerade eingefügte defaultValue. Wurde unter dem Schlüssel ausdrücklich undefined gespeichert, kommt undefined zurück, und nichts wird überschrieben.

Beispiele

Einfacher Fall: vorhandener und fehlender Schlüssel

const config = new Map([['theme', 'dark']]);

console.log(config.getOrInsert('theme', 'light')); // vorhanden → bleibt
console.log(config.getOrInsert('lang', 'de'));     // fehlt → wird eingefügt
console.log([...config]);
dark de [ [ 'theme', 'dark' ], [ 'lang', 'de' ] ]

Einträge nach Kategorie gruppieren

const produkte = [
  { name: 'Apfel', kategorie: 'Obst' },
  { name: 'Möhre', kategorie: 'Gemüse' },
  { name: 'Birne', kategorie: 'Obst' }
];

const gruppen = new Map();
for (const p of produkte) {
  // Beim ersten Treffer ein leeres Array anlegen, danach das vorhandene nutzen
  gruppen.getOrInsert(p.kategorie, []).push(p.name);
}

console.log(Object.fromEntries(gruppen));
{ Obst: [ 'Apfel', 'Birne' ], 'Gemüse': [ 'Möhre' ] }

Wörter zählen

const text = 'das ist das Haus vom Nikolaus das';
const zaehler = new Map();

for (const wort of text.split(' ')) {
  zaehler.set(wort, zaehler.getOrInsert(wort, 0) + 1);
}

console.log(zaehler.get('das'));
3

Fallback für Umgebungen ohne Unterstützung

const getOrInsert = (map, key, defaultValue) => {
  if (typeof map.getOrInsert === 'function') {
    return map.getOrInsert(key, defaultValue);
  }
  if (!map.has(key)) map.set(key, defaultValue);
  return map.get(key);
};

const cache = new Map();
console.log(getOrInsert(cache, 'user:1', { visits: 0 }));
{ visits: 0 }

// Wichtig · Fallstricke

  • Kompatibilität: Die Methode stammt aus dem TC39-Proposal „Upsert“ (Stage 3) und ist erst in neueren Browser- und Engine-Versionen verfügbar. Für Produktivcode braucht man Feature-Erkennung (typeof Map.prototype.getOrInsert === 'function') oder ein Polyfill, etwa aus core-js.
  • Eifrige Auswertung: map.getOrInsert(k, []) erzeugt bei jedem Aufruf ein neues Array, auch wenn es verworfen wird. Bei teuren Standardwerten (Objekte mit großem Aufbau, Netzwerk- oder DOM-Zugriffe) ist getOrInsertComputed(key, callback) die bessere Wahl.
  • Keine Überschreibung: Anders als bei map.get(k) ?? defaultValue wird ein ausdrücklich gespeicherter Wert wie undefined oder null nicht ersetzt. Maßgeblich ist nur, ob der Schlüssel existiert.
  • Objekt-Schlüssel werden über ihre Identität verglichen: getOrInsert({}, 1) legt jedes Mal einen neuen Eintrag an.
  • Die gleiche Methode gibt es auch als WeakMap.prototype.getOrInsert(). Dort sind nur Objekte (und nicht registrierte Symbole) als Schlüssel erlaubt.