Signatur
Beschreibung
Mit new EventTarget() erhältst du ein leichtgewichtiges Objekt mit den drei Methoden addEventListener(), removeEventListener() und dispatchEvent(). Das ist dasselbe Ereignissystem, das auch DOM-Knoten, window, WebSocket oder AbortSignal verwenden. Früher musste man dafür ein DOM-Element „missbrauchen“ oder eine eigene Event-Emitter-Bibliothek schreiben.
Am häufigsten nutzt man EventTarget als Basisklasse: Mit class Store extends EventTarget bekommen eigene Klassen (Stores, Services, Modelle) ein natives, standardkonformes Ereignissystem. In Verbindung mit CustomEvent kannst du Nutzdaten über die Eigenschaft detail übergeben.
Weil es die native API ist, funktionieren alle Listener-Optionen: once, passive, capture und vor allem signal, womit du Listener gesammelt per AbortController entfernen kannst. Das Event wird synchron ausgelöst: dispatchEvent() kehrt erst zurück, wenn alle Listener gelaufen sind.
Rückgabewert
EventTarget-Instanz ohne registrierte Listener.Beispiele
Einfaches EventTarget erzeugen und Ereignis auslösen
const bus = new EventTarget();
bus.addEventListener('ping', (event) => {
console.log(`Empfangen: ${event.type}`);
});
bus.dispatchEvent(new Event('ping'));
Eigene Klasse mit Ereignissen und CustomEvent-Daten
class Warenkorb extends EventTarget {
#artikel = [];
hinzufuegen(name, preis) {
this.#artikel.push({ name, preis });
this.dispatchEvent(new CustomEvent('change', {
detail: { anzahl: this.#artikel.length, summe: this.summe }
}));
}
get summe() {
return this.#artikel.reduce((s, a) => s + a.preis, 0);
}
}
const korb = new Warenkorb();
korb.addEventListener('change', ({ detail }) => {
console.log(`${detail.anzahl} Artikel, ${detail.summe.toFixed(2)} €`);
});
korb.hinzufuegen('Buch', 19.9);
korb.hinzufuegen('Stift', 2.5);
Listener per AbortController und once aufräumen
const status = new EventTarget();
const controller = new AbortController();
status.addEventListener('update', (e) => console.log('Update:', e.detail),
{ signal: controller.signal });
status.addEventListener('ready', () => console.log('Bereit!'), { once: true });
status.dispatchEvent(new CustomEvent('update', { detail: 1 }));
status.dispatchEvent(new Event('ready'));
status.dispatchEvent(new Event('ready')); // wird ignoriert (once)
controller.abort(); // entfernt den update-Listener
status.dispatchEvent(new CustomEvent('update', { detail: 2 })); // keine Ausgabe
// Wichtig · Fallstricke
- Kein Bubbling: Ein eigenständiges
EventTargethat keine Eltern.bubbles: trueund Capture-Phase haben daher keine Wirkung – nur der direkte Empfänger wird benachrichtigt. - Synchron:
dispatchEvent()ruft alle Listener sofort nacheinander auf. Wirft ein Listener eine Ausnahme, wird sie gemeldet (reportError), die übrigen Listener laufen aber weiter, unddispatchEvent()selbst wirft nicht. - Event-Objekte nicht wiederverwenden, solange sie ausgelöst werden: Ein Event, das gerade verarbeitet wird, erneut auszulösen, führt zu einem
InvalidStateError. - Derselbe Listener (gleiche Funktionsreferenz, gleiches
capture) wird nur einmal registriert. Zum Entfernen perremoveEventListener()brauchst du die identische Referenz – anonyme Pfeilfunktionen lassen sich so nicht entfernen, hier hilft die Optionsignal. - Kompatibilität: Der Konstruktor ist in älteren Browsern (Safari < 14, IE) nicht verfügbar; Unterklassen per
extendsbrauchen ebenfalls diese Versionen. In Node.js istEventTargetseit Version 15 global verfügbar (vorher experimentell) und unabhängig vom klassischenEventEmitter.