Signatur
Beschreibung
RegExp.$1 bis RegExp.$9 sind statische, nur lesbare Getter des globalen RegExp-Konstruktors. Nach jedem erfolgreichen Treffer, etwa durch RegExp.prototype.exec(), test(), String.prototype.match() oder replace(), speichert die Engine die ersten neun Klammergruppen (Capturing Groups) global. RegExp.$1 enthält die erste Gruppe, RegExp.$2 die zweite und so weiter.
Die Eigenschaften stammen aus der Anfangszeit von JavaScript und sind an Perl angelehnt. Sie gelten heute als veraltet. Sie stehen nur deshalb in der Spezifikation (Annex B, „Legacy RegExp features“), damit alter Code weiterläuft. Weil der Zustand global an einem Objekt hängt, kann jeder weitere Regex-Aufruf die Werte überschreiben, auch einer aus einer Bibliothek oder einem Callback.
In neuem Code solltest du die Gruppen immer direkt aus dem Ergebnis lesen: aus dem Array von exec() oder match(), aus matchAll(), über benannte Gruppen ((?<name>…) und match.groups) oder in replace() über die Ersetzungsmuster $1 bzw. die Parameter der Callback-Funktion. Die Ersetzungsmuster im String haben mit diesen statischen Eigenschaften nichts zu tun, auch wenn sie gleich aussehen.
Rückgabewert
"" und nicht undefined.Beispiele
Grundlegende Nutzung nach test()
const re = /(\d{4})-(\d{2})-(\d{2})/;
if (re.test('Termin: 2024-05-17')) {
// Veralteter Weg: globale statische Eigenschaften
console.log(RegExp.$1, RegExp.$2, RegExp.$3);
}
Fallstrick: Werte werden vom nächsten Treffer überschrieben
/(\w+)@(\w+)\.de/.test('info@beispiel.de');
console.log(RegExp.$1); // info
// Irgendein anderer Regex-Aufruf, z. B. in einer Hilfsfunktion
'Preis: 42 €'.match(/(\d+)/);
console.log(RegExp.$1); // Der Benutzername ist verloren
console.log(JSON.stringify(RegExp.$2)); // Gruppe 2 existiert nicht mehr
Moderne Alternative: exec() mit benannten Gruppen
const re = /(?<jahr>\d{4})-(?<monat>\d{2})-(?<tag>\d{2})/;
const treffer = re.exec('Termin: 2024-05-17');
if (treffer) {
const { jahr, monat, tag } = treffer.groups;
console.log(`${tag}.${monat}.${jahr}`);
console.log(treffer[1]); // gleichwertig zu RegExp.$1, aber lokal
}
Richtiges Ersetzen: $1 im Ersetzungsstring statt RegExp.$1
const name = 'Mustermann, Max';
// $2 und $1 sind hier Ersetzungsmuster, keine statischen Eigenschaften
const umgedreht = name.replace(/(\w+),\s*(\w+)/, '$2 $1');
console.log(umgedreht);
// Oder mit Callback und benannten Parametern
const mitCallback = name.replace(/(\w+),\s*(\w+)/, (_, nach, vor) => `${vor} ${nach}`);
console.log(mitCallback);
// Wichtig · Fallstricke
- Veraltet: Nutze die Eigenschaften nicht in neuem Code. Es gibt einen TC39-Vorschlag („Legacy RegExp features“), sie für Unterklassen von
RegExpund für Regex-Objekte aus anderen Realms zu sperren. In solchen Fällen kann der Zugriff dann einenTypeErrorauslösen. - Globaler Zustand: Die Werte gehören zum ganzen Realm, nicht zu einem bestimmten Regex. Jeder erfolgreiche Treffer überschreibt sie, auch einer in fremdem Code, in Event-Handlern oder nach einem
await. Nur fehlgeschlagene Treffer lassen die alten Werte stehen, was ebenso leicht zu Fehlern führt. - Nur 9 Gruppen: Ab der zehnten Gruppe gibt es kein
RegExp.$10. Benannte Gruppen sind auch nicht direkt abrufbar. - Leerer String statt
undefined: Nicht vorhandene oder nicht beteiligte Gruppen liefern"". Deshalb lässt sich „leer erfasst“ nicht von „nicht erfasst“ unterscheiden, anders als beim Ergebnis-Array vonexec(). - Nur lesbar: Eine Zuweisung wie
RegExp.$1 = 'x'wird im nicht-strikten Modus einfach ignoriert. Im Strict Mode löst sie einenTypeErroraus. - Performance: Engines müssen diesen Zustand nach jedem Treffer mitführen. Der Zugriff darauf kann Optimierungen verhindern.
- Kompatibilität: Vorhanden in allen Browsern und in Node.js, aber als veraltet markiert. TypeScript und Linter (z. B. ESLint mit
no-restricted-properties) warnen oft davor.