Start · Sprachen · JavaScript · Referenz · Map[Symbol.species]

Map[Symbol.species]

Eigenschaft

Statischer Getter, der den Konstruktor liefert, mit dem abgeleitete Map-Objekte erzeugt würden. Standardmäßig ist das <code>this</code>. Die eingebauten Map-Methoden verwenden ihn nicht.

seit JavaScript ES2015 Kategorie: method-property

Signatur

get Map[Symbol.species]

Beschreibung

Map[Symbol.species] ist eine statische Accessor-Eigenschaft (nur Getter). Sie gibt den Wert von this zurück, also den Konstruktor, über den sie aufgerufen wird. Bei Map selbst ist das Map, bei einer Unterklasse class MyMap extends Map {} ist es MyMap.

Das Protokoll Symbol.species gibt es, damit eingebaute Methoden, die neue Instanzen desselben Typs erzeugen, bei Unterklassen den richtigen Konstruktor verwenden. Beispiele sind Array.prototype.map() oder Promise.prototype.then(). Unterklassen können den Getter überschreiben und so festlegen, welcher Konstruktor für abgeleitete Objekte verwendet wird.

Bei Map ist die Eigenschaft allerdings ungenutzt: Keine eingebaute Methode von Map.prototype erzeugt eine neue Map aus einer bestehenden. Auch das neuere Map.groupBy() fragt Symbol.species nicht ab. Die Eigenschaft ist hauptsächlich aus Gründen der Einheitlichkeit mit anderen eingebauten Klassen vorhanden. Eigene Methoden, die Kopien erzeugen, können sie aber bewusst auswerten.

Rückgabewert

Typ
Function
Beschreibung
Der Wert von this, also der Konstruktor, über den auf die Eigenschaft zugegriffen wird (z. B. Map oder eine Unterklasse).

Beispiele

Standardwert bei Map und Unterklassen

class CacheMap extends Map {}

console.log(Map[Symbol.species] === Map);
console.log(CacheMap[Symbol.species] === CacheMap);
true true

Species in einer eigenen Kopiermethode auswerten

class TrackedMap extends Map {
  // Kopien sollen ganz normale Maps sein
  static get [Symbol.species]() {
    return Map;
  }

  filter(predicate) {
    const Species = this.constructor[Symbol.species];
    const result = new Species();
    for (const [key, value] of this) {
      if (predicate(value, key)) result.set(key, value);
    }
    return result;
  }
}

const prices = new TrackedMap([["Apfel", 1.2], ["Mango", 2.5], ["Birne", 0.9]]);
const cheap = prices.filter((price) => price < 2);

console.log(cheap instanceof TrackedMap, cheap instanceof Map);
console.log([...cheap.keys()]);
false true [ 'Apfel', 'Birne' ]

Eingebaute Methoden ignorieren Species

class NoSpecies extends Map {
  static get [Symbol.species]() {
    throw new Error("wird nie aufgerufen");
  }
}

const m = new NoSpecies([["a", 1]]);
// Keine Map-Methode fragt Symbol.species ab – es wird kein Fehler geworfen
m.set("b", 2);
m.forEach((v, k) => console.log(k, v));
console.log(Map.groupBy([1, 2, 3], (n) => (n % 2 ? "ungerade" : "gerade")));
a 1 b 2 Map(2) { 'ungerade' => [ 1, 3 ], 'gerade' => [ 2 ] }

// Wichtig · Fallstricke

  • Keine Auswirkung auf eingebaute Methoden: Wenn du Symbol.species in einer Map-Unterklasse überschreibst, ändert das am Verhalten von Map.prototype nichts. Die Eigenschaft wirkt nur in eigenem Code, der sie ausdrücklich abfragt.
  • Die Eigenschaft hat nur einen Getter und keinen Setter. Eine Zuweisung wie Map[Symbol.species] = X wird im nicht-strikten Modus stillschweigend ignoriert und löst im Strict Mode einen TypeError aus. Zum Überschreiben verwendest du static get [Symbol.species]() in einer Unterklasse oder Object.defineProperty.
  • Ein neuer Konstruktoraufruf wie new MyMap(original) nutzt Species nicht. Er erzeugt immer eine Instanz der aufgerufenen Klasse.
  • Im Zusammenhang mit Symbol.species gab es Sicherheits- und Performance-Bedenken. Es gibt deshalb TC39-Überlegungen, die Unterstützung einzuschränken. Neuer Code sollte sich nicht darauf verlassen.
  • Kompatibilität: Wird von allen modernen Browsern und von Node.js ab 6.5 unterstützt.