Signatur
Beschreibung
Die statische Accessor-Eigenschaft TypedArray[Symbol.species] gibt den Konstruktor zurück, mit dem Methoden eines typisierten Arrays ihre Rückgabewerte erzeugen. Die Standardimplementierung gibt einfach this zurück. Beim Aufruf über Float32Array ist das also Float32Array, bei einer Unterklasse die Unterklasse selbst.
Methoden, die ein neues typisiertes Array anlegen, fragen diesen Konstruktor über instance.constructor[Symbol.species] ab. Dazu gehören filter(), map(), slice() und subarray(). Methoden wie toSorted(), toReversed() und with() nutzen den Species-Mechanismus dagegen nicht. Sie geben immer eine Instanz des eingebauten Grundtyps zurück, etwa Uint8Array.
Nützlich ist die Eigenschaft vor allem, wenn du von einem typisierten Array erbst. Überschreibst du static get [Symbol.species]() in deiner Unterklasse, bestimmst du selbst, welchen Typ abgeleitete Ergebnisse haben. Ein häufiger Fall: Zusatzmethoden der Unterklasse sollen nicht an Zwischenergebnisse weitergegeben werden, oder deren Konstruktor erwartet andere Argumente als die Grundklasse.
Die Eigenschaft liegt am verborgenen, abstrakten %TypedArray%-Konstruktor, also dem Prototyp von Int8Array, Uint8Array, Float64Array und den anderen. Alle konkreten Typen erben sie von dort.
Rückgabewert
this, auf dem der Getter aufgerufen wurde, also der Konstruktor selbst, z. B. Int16Array oder eine eigene Unterklasse. Dieser Konstruktor erzeugt abgeleitete typisierte Arrays.Beispiele
Standardwert abfragen
console.log(Int8Array[Symbol.species] === Int8Array);
console.log(Float64Array[Symbol.species] === Float64Array);
// Der Getter liegt am abstrakten %TypedArray%-Konstruktor
const TypedArray = Object.getPrototypeOf(Uint8Array);
const desc = Object.getOwnPropertyDescriptor(TypedArray, Symbol.species);
console.log(typeof desc.get, desc.set);
Unterklasse: Ergebnisse von map() und filter() als Grundtyp
class Pixels extends Uint8ClampedArray {
// Abgeleitete Arrays sollen normale Uint8ClampedArrays sein
static get [Symbol.species]() {
return Uint8ClampedArray;
}
brighten(amount) {
return this.map((v) => v + amount);
}
}
const px = new Pixels([10, 200, 250]);
const bright = px.brighten(20);
console.log(px instanceof Pixels);
console.log(bright instanceof Pixels);
console.log(bright.constructor.name, [...bright]);
Standardverhalten: Unterklasse bleibt erhalten
class Samples extends Float32Array {
peak() {
return Math.max(...this);
}
}
const s = new Samples([0.1, -0.5, 0.9, 0.3]);
const positive = s.filter((x) => x > 0);
const part = s.subarray(1, 3);
// Ohne eigenes Symbol.species gilt this => Samples
console.log(positive instanceof Samples, positive.peak().toFixed(1));
console.log(part.constructor === Samples);
// toSorted() ignoriert Symbol.species
console.log(s.toSorted().constructor.name);
// Wichtig · Fallstricke
- Nur ein Getter: Die Eigenschaft hat keinen Setter.
Uint8Array[Symbol.species] = Xändert nichts und wirft im Strict Mode einenTypeError. Zum Überschreiben definierst du in einer Unterklassestatic get [Symbol.species]()oder nutztObject.defineProperty. - Ergebnis muss ein TypedArray sein: Der Species-Konstruktor muss ein typisiertes Array erzeugen. Sonst werfen
map(),slice()und die anderen einenTypeError. Gibt er ein Array zurück, das kürzer ist als verlangt, gibt es ebenfalls einen Fehler. Den Elementtyp darfst du wechseln (z. B. vonFloat32ArrayzuInt8Array), aberBigInt- undNumber-Typen darfst du nicht mischen. - Konstruktor-Signatur:
subarray()ruft den Species-Konstruktor mit(buffer, byteOffset, length)auf,map(),filter()undslice()mit einer Länge. Ein eigener Konstruktor mit anderen Parametern muss beide Aufrufformen verarbeiten können oder überSymbol.speciesauf den Grundtyp verweisen. - Nicht alle Methoden nutzen Species:
toSorted(),toReversed()undwith()(ES2023) sowieTypedArray.from()undTypedArray.of()wertenSymbol.speciesnicht aus.from()undof()verwendenthisdirekt. - Performance und Sicherheit: Der Species-Mechanismus macht Engine-Optimierungen schwerer und war schon Ursache von Sicherheitslücken. Es gibt einen TC39-Vorschlag, ihn einzuschränken. Überschreibe ihn nur, wenn es wirklich nötig ist.
- Kompatibilität: Wird seit ES2015 in allen modernen Browsern und in Node.js unterstützt, nicht aber im Internet Explorer.