Start · Sprachen · JavaScript · Referenz · Symbol.toPrimitive

Symbol.toPrimitive

Eigenschaft

Bekanntes Symbol, über das ein Objekt eine Methode festlegt, die bestimmt, wie es in einen primitiven Wert (<code>string</code>, <code>number</code>, …) umgewandelt wird.

seit JavaScript ES2015 Kategorie: method-property

Signatur

Symbol.toPrimitive

Beschreibung

Symbol.toPrimitive ist eine statische, schreibgeschützte Dateneigenschaft von Symbol und enthält eines der sogenannten bekannten Symbole (well-known symbols). Legt ein Objekt unter diesem Schlüssel eine Methode ab, ruft die JavaScript-Engine sie immer dann auf, wenn das Objekt in einen primitiven Wert umgewandelt werden muss, etwa bei +obj, `${obj}`, obj + "", obj == 5 oder String(obj).

Die Methode bekommt einen Hinweis (hint) als Zeichenkette mit, an dem sie erkennt, welcher Zieltyp erwartet wird: "number" (z. B. bei arithmetischen Operationen, Number() und Vergleichen mit </>), "string" (z. B. bei Template-Literalen, String() und Eigenschaftsschlüsseln) oder "default" (bei binärem + und bei ==). Ist die Methode vorhanden, hat sie Vorrang vor valueOf() und toString(). Diese beiden werden dann nicht mehr für die Umwandlung herangezogen.

Einsatzgebiete sind Wertobjekte wie Geldbeträge, Maßeinheiten oder Zeitangaben, die sich in Rechnungen wie Zahlen und in Textausgaben wie formatierte Zeichenketten verhalten sollen. In der Standardbibliothek setzen Date.prototype[Symbol.toPrimitive] und Symbol.prototype[Symbol.toPrimitive] dieses Symbol bereits ein.

Parameter

Name Typ Default Beschreibung
$hint Pflicht "number" | "string" | "default" Wird von der Engine an die Methode [Symbol.toPrimitive](hint) übergeben und gibt an, welcher primitive Typ bevorzugt wird. Symbol.toPrimitive selbst hat keine Parameter.

Rückgabewert

Typ
symbol
Beschreibung
Das bekannte Symbol Symbol.toPrimitive. Die unter diesem Schlüssel hinterlegte Methode muss einen primitiven Wert zurückgeben (string, number, bigint, boolean, symbol, null oder undefined).

Beispiele

Welcher Hinweis kommt wann an?

const obj = {
  [Symbol.toPrimitive](hint) {
    console.log('hint:', hint);
    if (hint === 'number') return 42;
    if (hint === 'string') return 'zweiundvierzig';
    return 'default';
  }
};

console.log(+obj);        // number
console.log(`${obj}`);    // string
console.log(obj + '');    // default
console.log(obj == 'default'); // default
hint: number 42 hint: string zweiundvierzig hint: default default hint: default true

Geldbetrag-Klasse: rechnen und formatiert ausgeben

class Money {
  constructor(cents, currency = 'EUR') {
    this.cents = cents;
    this.currency = currency;
  }

  [Symbol.toPrimitive](hint) {
    if (hint === 'string') {
      return new Intl.NumberFormat('de-DE', {
        style: 'currency',
        currency: this.currency
      }).format(this.cents / 100);
    }
    // 'number' und 'default' liefern den Betrag in Euro
    return this.cents / 100;
  }
}

const preis = new Money(1999);
const versand = new Money(495);

console.log(preis + versand);          // Rechnen
console.log(`Preis: ${preis}`);        // Anzeige
console.log(preis > versand);          // Vergleich
24.94 Preis: 19,99 € true

Vorrang vor valueOf() und toString()

const temp = {
  valueOf: () => 1,
  toString: () => 'eins',
  [Symbol.toPrimitive]: (hint) => (hint === 'string' ? 'Symbol-String' : 99)
};

console.log(temp * 2);
console.log(String(temp));
198 Symbol-String

Eingebautes Verhalten von Date

const d = new Date(0);

console.log(typeof d[Symbol.toPrimitive]);
console.log(d[Symbol.toPrimitive]('number'));
// Date behandelt 'default' wie 'string'
console.log(typeof (d + 1));
function 0 string

// Wichtig · Fallstricke

  • Rückgabewert muss primitiv sein: Gibt die Methode ein Objekt zurück, wirft die Engine einen TypeError („Cannot convert object to primitive value“).
  • Kein Rückgriff auf valueOf/toString: Ist [Symbol.toPrimitive] definiert, ruft die Engine valueOf() und toString() für die Umwandlung nicht mehr auf. Alle drei Hinweise sollten deshalb sinnvoll behandelt werden.
  • Ist der Wert unter dem Schlüssel weder undefined noch null noch eine Funktion, wirft die Engine ebenfalls einen TypeError.
  • Der Hinweis "default" kommt bei binärem + und bei == an. Hier ist oft nicht klar, ob addiert oder verkettet werden soll. Deshalb sollte ein Objekt dafür eine eindeutige Konvention festlegen.
  • Die strikte Gleichheit === löst keine Umwandlung aus und ruft die Methode daher nie auf.
  • Die Eigenschaft selbst ist nicht beschreibbar, nicht aufzählbar und nicht konfigurierbar.
  • Kompatibilität: ES2015, wird von allen modernen Browsern und von Node.js ab 6 unterstützt. Im Internet Explorer fehlt die Unterstützung.