Start · Sprachen · JavaScript · Referenz · MutationRecord

MutationRecord

Schnittstelle

Beschreibt eine einzelne DOM-Änderung (Attribut, Textinhalt oder Kindknoten), die ein <code>MutationObserver</code> erfasst und an seinen Callback übergeben hat.

seit JavaScript Baseline: alle Browser (DOM4) Kategorie: webapi

Signatur

interface MutationRecord

Beschreibung

MutationRecord ist ein schreibgeschütztes Objekt, das der Browser selbst erzeugt. Man instanziiert es nie direkt: Ein MutationObserver sammelt DOM-Änderungen und übergibt seinem Callback ein Array solcher Einträge. Außerdem liefert MutationObserver.prototype.takeRecords() die noch nicht verarbeiteten Einträge.

Jeder Eintrag steht für genau eine Änderung. Welche Eigenschaften befüllt sind, hängt von type ab:

  • type – "attributes", "characterData" oder "childList".
  • target – der betroffene Knoten: bei Attributen das Element, bei characterData der Text-/Kommentarknoten, bei childList der Elternknoten.
  • addedNodes / removedNodes – eine NodeList der eingefügten bzw. entfernten Knoten (leer, wenn der Typ nicht childList ist).
  • previousSibling / nextSibling – Geschwisterknoten der eingefügten bzw. entfernten Knoten oder null.
  • attributeName / attributeNamespace – Name und Namensraum des geänderten Attributs (sonst null).
  • oldValue – vorheriger Wert, aber nur, wenn beim Beobachten attributeOldValue bzw. characterDataOldValue auf true gesetzt wurde; sonst null.

Typische Einsatzfälle: dynamisch nachgeladene Elemente erkennen (z. B. Widgets initialisieren), Attributänderungen verfolgen (Klassen, aria-*), Undo-Funktionen für contenteditable oder Debugging von Code anderer Hersteller, der das DOM verändert.

Parameter

Name Typ Default Beschreibung
$type Pflicht "attributes" | "characterData" | "childList" Schreibgeschützt. Art der Änderung.
$target Pflicht Node Schreibgeschützt. Knoten, an dem die Änderung stattfand (bei childList der Elternknoten).
$addedNodes Pflicht NodeList leere NodeList Schreibgeschützt. Eingefügte Knoten (nur bei childList).
$removedNodes Pflicht NodeList leere NodeList Schreibgeschützt. Entfernte Knoten (nur bei childList).
$previousSibling Node | null null Schreibgeschützt. Vorheriges Geschwister der eingefügten/entfernten Knoten.
$nextSibling Node | null null Schreibgeschützt. Nächstes Geschwister der eingefügten/entfernten Knoten.
$attributeName string | null null Schreibgeschützt. Lokaler Name des geänderten Attributs.
$attributeNamespace string | null null Schreibgeschützt. Namensraum des geänderten Attributs (z. B. bei SVG/XLink).
$oldValue string | null null Schreibgeschützt. Alter Wert des Attributs bzw. Textes – nur mit attributeOldValue/characterDataOldValue: true.

Rückgabewert

Typ
MutationRecord
Beschreibung
Wird nicht vom Nutzer erzeugt, sondern als Element des Arrays MutationRecord[] an den MutationObserver-Callback bzw. von takeRecords() geliefert.

Beispiele

Einträge im Callback nach Typ auswerten

const liste = document.createElement('ul');
document.body.append(liste);

const observer = new MutationObserver((records) => {
  for (const record of records) {
    switch (record.type) {
      case 'childList':
        console.log('Hinzugefügt:', record.addedNodes.length, 'Entfernt:', record.removedNodes.length);
        break;
      case 'attributes':
        console.log(`Attribut ${record.attributeName}: "${record.oldValue}" → "${record.target.getAttribute(record.attributeName)}"`);
        break;
    }
  }
});

observer.observe(liste, { childList: true, attributes: true, attributeOldValue: true });

liste.append(document.createElement('li'));
liste.className = 'aktiv';
Hinzugefügt: 1 Entfernt: 0 Attribut class: "null" → "aktiv"

Nachgeladene Elemente automatisch initialisieren

const initTooltip = (el) => {
  el.title = el.dataset.tooltip;
  console.log('Tooltip initialisiert:', el.dataset.tooltip);
};

const observer = new MutationObserver((records) => {
  for (const { addedNodes } of records) {
    for (const node of addedNodes) {
      // Nur Elemente prüfen, Textknoten ignorieren
      if (node.nodeType !== Node.ELEMENT_NODE) continue;
      if (node.matches('[data-tooltip]')) initTooltip(node);
      node.querySelectorAll('[data-tooltip]').forEach(initTooltip);
    }
  }
});

observer.observe(document.body, { childList: true, subtree: true });

const btn = document.createElement('button');
btn.dataset.tooltip = 'Speichern';
document.body.append(btn);
Tooltip initialisiert: Speichern

Textänderungen mit altem Wert und takeRecords()

const absatz = document.createElement('p');
absatz.textContent = 'Entwurf';
document.body.append(absatz);

const observer = new MutationObserver(() => {});
observer.observe(absatz, { characterData: true, subtree: true, characterDataOldValue: true });

absatz.firstChild.data = 'Final';

// Ausstehende Einträge synchron abholen, bevor der Callback läuft
const [record] = observer.takeRecords();
console.log(record.type, record.oldValue, '→', record.target.data);
observer.disconnect();
characterData Entwurf → Final

// Wichtig · Fallstricke

  • Asynchron und gebündelt: Die Einträge kommen als Mikrotask nach der Änderung an, mehrere Änderungen landen in einem Array. target spiegelt den aktuellen Zustand wider, nicht den Zustand zum Zeitpunkt der Änderung. Bei mehreren Änderungen hintereinander kann der aktuelle Wert also schon „weiter“ sein als der Eintrag.
  • oldValue ist oft null: Es wird nur befüllt, wenn attributeOldValue bzw. characterDataOldValue gesetzt ist. Bei childList ist es immer null.
  • addedNodes enthält auch Textknoten und nur die direkt eingefügten Wurzelknoten. Deren Nachfahren muss man selbst mit querySelectorAll durchsuchen. Ein Knoten kann in einem Stapel zugleich in addedNodes und removedNodes auftauchen (z. B. bei Verschiebungen). Prüfe deshalb node.isConnected.
  • innerHTML/textContent am Element erzeugen childList-Einträge und kein characterData. Letzteres entsteht nur, wenn man einen bestehenden Textknoten direkt ändert (data, nodeValue).
  • Performance: Mit subtree: true auf document.body können sehr viele Einträge entstehen. Halte den Callback schlank, filtere früh und rufe disconnect() auf, wenn du nicht mehr beobachten musst. Ändert der Callback selbst das beobachtete DOM, kann eine Endlosschleife entstehen.
  • Die Eigenschaften sind schreibgeschützt. Es gibt keinen öffentlichen Konstruktor, new MutationRecord() wirft einen TypeError.
  • Wird von allen aktuellen Browsern unterstützt. Das veraltete Mutation-Events-API (DOMNodeInserted u. a.) ist deprecated und wurde teilweise entfernt. Verwende stattdessen MutationObserver.