Signatur
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
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));
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));
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.
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));
// Wichtig · Fallstricke
- TypeError bei ungültigem Schlüssel: Primitive Werte (
string,number,boolean,null,undefined,bigint) und registrierte Symbole ausSymbol.for()lösen einenTypeErroraus. - 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
valueauf seinen eigenen Schlüssel, ist das unproblematisch, weilWeakMapintern 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 keinsize. Wer das braucht, nimmtMap. - Schlüssel werden nach Identität verglichen: Zwei inhaltsgleiche Objekte wie
{}und{}sind zwei verschiedene Schlüssel. set()muss auf einer echtenWeakMapaufgerufen werden. Ein Aufruf mit anderemthis(z. B. übercall) löst einenTypeErroraus.