Signatur
Beschreibung
ArrayBuffer[Symbol.species] ist eine statische Zugriffseigenschaft, also ein Getter ohne Setter. Sie legt fest, welcher Konstruktor benutzt wird, wenn eine ArrayBuffer-Methode aus einem vorhandenen Buffer einen neuen Buffer erzeugt. Die Standard-Umsetzung gibt einfach this zurück. Beim Aufruf auf ArrayBuffer ist das also ArrayBuffer selbst, bei einer Unterklasse die Unterklasse.
Praktisch betrifft das vor allem ArrayBuffer.prototype.slice(). Die Methode liest this.constructor[Symbol.species] aus und erzeugt damit den Ergebnis-Buffer. Leitet man von ArrayBuffer ab, liefert slice() deshalb automatisch wieder eine Instanz der Unterklasse. Die neueren Methoden transfer() und transferToFixedLength() beachten Symbol.species nicht. Sie erzeugen immer ein normales ArrayBuffer.
Man überschreibt die Eigenschaft in einer Unterklasse mit static get [Symbol.species](). Das lohnt sich, wenn abgeleitete Ergebnisse wieder schlichte ArrayBuffer-Objekte sein sollen, etwa weil der Konstruktor der Unterklasse zusätzliche Argumente erwartet oder Nebenwirkungen hat.
Rückgabewert
this, also der Konstruktor, auf dem der Getter aufgerufen wurde. Mit ihm werden neue Buffer in slice() erzeugt.Beispiele
Standardwert abfragen
// Standardmäßig liefert der Getter einfach den Konstruktor selbst zurück
console.log(ArrayBuffer[Symbol.species] === ArrayBuffer);
// Auch über eine Instanz erreichbar
const buf = new ArrayBuffer(16);
console.log(buf.constructor[Symbol.species] === ArrayBuffer);
Unterklasse: slice() liefert die Unterklasse
class ChunkBuffer extends ArrayBuffer {
describe() {
return `ChunkBuffer mit ${this.byteLength} Bytes`;
}
}
const chunk = new ChunkBuffer(8);
const part = chunk.slice(0, 4);
console.log(ChunkBuffer[Symbol.species] === ChunkBuffer);
console.log(part instanceof ChunkBuffer);
console.log(part.describe());
Species überschreiben: slice() liefert ein normales ArrayBuffer
class LoggedBuffer extends ArrayBuffer {
constructor(length) {
super(length);
console.log(`LoggedBuffer angelegt: ${length} Bytes`);
}
// Abgeleitete Buffer sollen normale ArrayBuffer sein, also ohne Logging
static get [Symbol.species]() {
return ArrayBuffer;
}
}
const logged = new LoggedBuffer(32);
const copy = logged.slice(0, 16);
console.log(copy instanceof LoggedBuffer);
console.log(copy.constructor === ArrayBuffer);
transfer() beachtet Species nicht
class MyBuffer extends ArrayBuffer {}
const original = new MyBuffer(8);
const moved = original.transfer();
console.log(moved instanceof MyBuffer);
console.log(original.detached);
// Wichtig · Fallstricke
- Prüfungen in
slice(): Das Objekt, das der Species-Konstruktor erzeugt, muss ein echtes, nicht geteiltesArrayBuffersein. Es darf nicht das Ausgangsobjekt selbst sein, darf nicht abgekoppelt (detached) sein und muss mindestens so viele Bytes haben wie angefordert. Sonst wirftslice()einenTypeError. - Nur Getter: Es gibt keinen Setter. Eine Zuweisung wie
ArrayBuffer[Symbol.species] = Xändert nichts und wirft im Strict Mode einen Fehler. Zum Überschreiben nimmt manstatic get [Symbol.species]()in einer Unterklasse oderObject.defineProperty(). - Ausnahmen:
transfer()undtransferToFixedLength()(ES2024) sowieresize()wertenSymbol.speciesnicht aus. - Sicherheit und Performance: Mit
Symbol.specieskann Fremdcode festlegen, welcher Konstruktor aufgerufen wird. Das war in der Vergangenheit eine Quelle von Engine-Sicherheitslücken und verlangsamt Optimierungen. In sicherheitskritischem Code sollte man nicht darauf bauen und stattdessen Buffer ausdrücklich mitnew ArrayBuffer()erzeugen. SharedArrayBufferhat einen eigenenSharedArrayBuffer[Symbol.species]mit gleichem Verhalten.- Unterstützt von allen modernen Browsern und von Node.js ab Version 6.5.