Start · Sprachen · JavaScript · Referenz · WeakMap.prototype.set()

WeakMap.prototype.set()

Methode

Fügt einer <code>WeakMap</code> einen Eintrag mit Objekt- oder Symbol-Schlüssel hinzu oder aktualisiert ihn und gibt die <code>WeakMap</code> selbst zurück.

seit JavaScript ES2015 (Symbol-Schlüssel: ES2023) Kategorie: method-property

Signatur

WeakMap.prototype.set(key, value)

Beschreibung

set() speichert einen Wert unter einem Schlüssel in einer WeakMap. Gibt es den Schlüssel schon, wird der alte Wert überschrieben. Der Schlüssel muss ein Objekt oder ein nicht registriertes Symbol sein. Primitive Werte wie Zeichenketten oder Zahlen sind nicht erlaubt.

Die WeakMap hält ihre Schlüssel nur schwach: Gibt es sonst keine Referenz mehr auf ein Schlüsselobjekt, kann die Speicherbereinigung (Garbage Collection) das Objekt samt Eintrag entfernen. Deshalb eignet sich set() gut, um Zusatzdaten an fremde Objekte zu hängen, ohne ein Speicherleck zu verursachen. Typische Fälle sind private Daten zu Klasseninstanzen, Metadaten zu DOM-Elementen oder Caches für berechnete Ergebnisse.

Weil set() die WeakMap selbst zurückgibt, lassen sich mehrere Aufrufe verketten: wm.set(a, 1).set(b, 2).

Parameter

Name Typ Default Beschreibung
$key Pflicht object | symbol Schlüssel des Eintrags. Erlaubt sind ein Objekt (auch Funktionen, Arrays, DOM-Knoten) oder ein nicht registriertes Symbol. Ein über Symbol.for() erzeugtes Symbol ist nicht erlaubt.
$value Pflicht any Beliebiger Wert, der unter dem Schlüssel gespeichert wird. Der Wert wird stark gehalten, solange der Schlüssel existiert.

Rückgabewert

Typ
WeakMap
Beschreibung
Dieselbe WeakMap-Instanz. Dadurch lassen sich Aufrufe verketten.

Beispiele

Einträge hinzufügen, überschreiben und verketten

const wm = new WeakMap();
const user = { name: 'Anna' };
const admin = { name: 'Ben' };

// Verketten ist möglich, weil set() die WeakMap zurückgibt
wm.set(user, { visits: 1 }).set(admin, { visits: 5 });

// Bestehenden Schlüssel überschreiben
wm.set(user, { visits: 2 });

console.log(wm.get(user));
console.log(wm.has(admin));
{ visits: 2 } true

Private Daten zu Klasseninstanzen

const privateData = new WeakMap();

class Konto {
  constructor(inhaber, saldo) {
    privateData.set(this, { saldo });
    this.inhaber = inhaber;
  }
  einzahlen(betrag) {
    const daten = privateData.get(this);
    privateData.set(this, { saldo: daten.saldo + betrag });
    return this;
  }
  get saldo() {
    return privateData.get(this).saldo;
  }
}

const konto = new Konto('Clara', 100).einzahlen(50);
console.log(konto.saldo);
console.log(Object.keys(konto));
150 [ 'inhaber' ]

Metadaten an DOM-Elemente hängen

const clickCounts = new WeakMap();

document.querySelectorAll('button').forEach((btn) => {
  clickCounts.set(btn, 0);
  btn.addEventListener('click', () => {
    clickCounts.set(btn, clickCounts.get(btn) + 1);
    console.log(`${btn.textContent}: ${clickCounts.get(btn)} Klicks`);
  });
});
// Wird ein Button aus dem DOM entfernt und nicht mehr referenziert,
// kann auch sein Zähler-Eintrag vom Garbage Collector entfernt werden.
z. B. "Speichern: 1 Klicks"

Ungültige Schlüssel lösen einen TypeError aus

const wm = new WeakMap();

try {
  wm.set('id-42', 'Wert');
} catch (err) {
  console.log(err instanceof TypeError);
}

try {
  wm.set(Symbol.for('global'), 1);
} catch (err) {
  console.log('Registriertes Symbol abgelehnt');
}

// Nicht registriertes Symbol (ab ES2023)
const sym = Symbol('lokal');
wm.set(sym, 'ok');
console.log(wm.get(sym));
true Registriertes Symbol abgelehnt ok

// Wichtig · Fallstricke

  • TypeError bei ungültigem Schlüssel: Primitive Werte (string, number, boolean, null, undefined, bigint) und registrierte Symbole aus Symbol.for() lösen einen TypeError aus.
  • Symbol-Schlüssel gibt es erst seit ES2023 (Chrome 108, Firefox 145?, Safari 16.4?). In älteren Umgebungen sind nur Objekte als Schlüssel erlaubt. Wer sicher gehen will, verwendet Objekte.
  • Wert hält Schlüssel am Leben: Verweist der gespeicherte value auf seinen eigenen Schlüssel, ist das unproblematisch, weil WeakMap intern wie ein Ephemeron arbeitet. Hält aber ein anderes, noch erreichbares Objekt eine Referenz auf den Schlüssel, bleibt der Eintrag bestehen.
  • Nicht aufzählbar: Über Einträge, die mit set() angelegt wurden, kann man nicht iterieren, und es gibt kein size. Wer das braucht, nimmt Map.
  • Schlüssel werden nach Identität verglichen: Zwei inhaltsgleiche Objekte wie {} und {} sind zwei verschiedene Schlüssel.
  • set() muss auf einer echten WeakMap aufgerufen werden. Ein Aufruf mit anderem this (z. B. über call) löst einen TypeError aus.