Signatur
Beschreibung
RegExp[Symbol.species] ist eine statische Zugriffseigenschaft (Getter) des RegExp-Konstruktors. Die Standardimplementierung gibt einfach this zurück, also den Konstruktor, über den die Eigenschaft abgefragt wird. Bei RegExp selbst ist das RegExp, bei einer Unterklasse class MyRegExp extends RegExp {} dagegen MyRegExp.
Gebraucht wird der Wert intern von Methoden, die eine Kopie des regulären Ausdrucks anlegen müssen, bevor sie arbeiten können:
RegExp.prototype[Symbol.split](), aufgerufen vonString.prototype.split(). Die Kopie bekommt zusätzlich das Flagy(sticky).RegExp.prototype[Symbol.matchAll](), aufgerufen vonString.prototype.matchAll(). Die Kopie bekommt eine eigenelastIndex-Position, damit das Original nicht verändert wird.
Beide Methoden ermitteln den Konstruktor über die abstrakte Operation SpeciesConstructor. Sie lesen zuerst regex.constructor und dann dessen [Symbol.species]. Über einen eigenen statischen Getter kann eine Unterklasse also festlegen, dass diese internen Kopien als einfache RegExp-Objekte entstehen und nicht als Instanzen der Unterklasse. Das ist sinnvoll, wenn der Konstruktor der Unterklasse Nebenwirkungen hat (Protokollierung, Prüfungen) oder eine andere Parameterliste erwartet.
Für den Alltag ist die Eigenschaft selten wichtig. Relevant wird sie, wenn Sie RegExp ableiten und steuern wollen, wie sich die Unterklasse bei split() und matchAll() verhält.
Rückgabewert
this, also den Konstruktor, über den die Eigenschaft abgefragt wurde (RegExp oder eine Unterklasse). Mit einem eigenen Getter kann eine Unterklasse einen anderen Konstruktor zurückgeben.Beispiele
Standardwert bei RegExp und Unterklassen
class MyRegExp extends RegExp {}
console.log(RegExp[Symbol.species] === RegExp);
console.log(MyRegExp[Symbol.species] === MyRegExp);
// Der Getter ist auf RegExp definiert und wird vererbt
const desc = Object.getOwnPropertyDescriptor(RegExp, Symbol.species);
console.log(typeof desc.get, desc.set);
split() erzeugt intern eine Kopie über species
class LoggingRegExp extends RegExp {
constructor(...args) {
super(...args);
console.log(`Neue Instanz: /${this.source}/${this.flags}`);
}
}
const sep = new LoggingRegExp('-');
const teile = 'a-b-c'.split(sep);
console.log(teile);
species überschreiben: interne Kopien als normales RegExp
class Tracked extends RegExp {
constructor(...args) {
super(...args);
console.log(`Tracked erstellt: /${this.source}/${this.flags}`);
}
// Interne Kopien sollen keine Tracked-Instanzen sein
static get [Symbol.species]() {
return RegExp;
}
}
const re = new Tracked('\\d', 'g');
const zahlen = [...'a1b2c3'.matchAll(re)].map((m) => m[0]);
console.log(zahlen);
console.log(re.lastIndex); // Original bleibt unverändert
// Wichtig · Fallstricke
- Nur
splitundmatchAll:match(),replace(),search(),test()undexec()legen keine Kopie an und lesenSymbol.speciesnicht. - Umweg über
constructor: Zuerst wirdregex.constructorgelesen. Ist dasundefined, wirdRegExpverwendet. Ist es kein Objekt, gibt es einenTypeError. Ist[Symbol.species]undefinedodernull, wird ebenfallsRegExpverwendet. - Kein Setter: Eine einfache Zuweisung wie
MyRegExp[Symbol.species] = RegExphat keine Wirkung (im Strict Mode gibt es einenTypeError). Überschreiben Sie den Wert mit einemstatic get [Symbol.species]()oder mitObject.defineProperty(). - Kopien werden aufgerufen: Der species-Konstruktor wird mit
(regex, flags)aufgerufen. Erwartet der Konstruktor Ihrer Unterklasse eine andere Parameterliste, gibt es Fehler. Geben Sie dannRegExpals species zurück. - Leistung: Wenn
RegExpoderRegExp.prototypeverändert wird, etwa beim globalen Überschreiben vonSymbol.species, schalten Engines wie V8 ihre schnellen Pfade für reguläre Ausdrücke ab. Ändern Sie den Wert nur in Unterklassen, niemals direkt anRegExp. - Kompatibilität: Wird von allen modernen Browsern und Node.js 6.5+ unterstützt (Baseline), nicht vom Internet Explorer. Es gibt Diskussionen im TC39,
Symbol.specieslangfristig einzuschränken. Neuer Code sollte sich deshalb möglichst nicht darauf stützen.