zonk: Typecasting in verschiedenen Kontexten

Beitrag lesen

Hallo Tim,

vielen Dank für Deine ausführliche Antwort. Ich habe mir Deinen Post durchgelesen und werde mir das auch mal sichern und Deinen Links nachgehen.

Ich habe jetzt einige neue Fragen zu Deiner Antwort.

Die Krux liegt darin, wie der Ausdruck ausgewertet wird, daraus folgt die Typumwandlung.

Genau das ist mein Problem:)

alert("Das Objekt " + o1);
"Das Objekt 1"

Hier befinden wir uns in einem Additions-Ausdruck.

Ist hier mit Additionsausdruck sowohl eine numerische Addition als auch Konkatenation gemeint?

Egal, was mir nicht einleuchtet, ist, wie der Interpreter bei unterschiedlichen Datentypen vorgeht. Logisch (jedenfalls für mich) wäre es, wenn es eine einheitliche Regel gäbe, wie verschiedene Datentypen verbunden werden. Bei skalaren Werten scheint das ja auch so zu sein

x = "30" + 30;

Wann immer eine Zeichenkette mit einer Zahl über diesen Operator verbunden wird, wird die Zahl zuvor in eine Zeichenkette umgewandelt.

Hier werden, wenn nur einer der beiden Werte vom Typ String ist, die gesamten Zahlenadditionsschritte übersprungen. Mache ich auch mal.

Das trifft ja bei "Das Objekt " + o1 zu.

Neben internen Funktionen haben Objekte auch noch interne Methoden. [[DefaultValue]] ist dazu zuständig einen konkreten Wert zu kreieren. Entweder als String mit toString() oder als „Wert“mit valueOf(). Zusätzlich kriegt diese interne Methode noch ein optionales Argument PreferredType als Vorschlag übergeben, mögliche Werte sind String und Number. ToPrimitive kriegt diesen möglichen Hint auch übergeben und gibt den auch weiter. Die nervige Schritt-für-Schritt-Beschreibung mal zusammengefasst:

Es ist also wegen toPrimitive nicht haltbar, wenn man sagt, primitive
Werte würden bei der Benutzung temporär in entsprechende Objekte (String, Number, Boolean) umgewandelt?

• Wenn der Hint „String“ ist:

Woraus ergibt sich der Hint? Aus dem Kontext (Operatoren, bestimmter Datentyp, den eine Funktion verlangt)?

Und was ist, wenn kein Hint da ist?

»»

Was könnte eine solche Situation auslösen?

When the [[DefaultValue]] method of O is called with no hint, then it behaves
  as if the hint were Number, unless O is a Date object (see 15.9), in which
  case it behaves as if the hint were String.

In unserem Fall sieht die interne Abfolge also so aus:

  1. "Objekt " + o1 ruft intern ToPrimitive(o1) auf.
  2. Das ruft o1.[[DefaultValue]] auf.
  3. Dieses gibt den Wert von o1.valueOf() zurück - Dein "1"-String.

Warum setzt der Additionsausdruck keinen Hint? Vermutlich, weil er für beides, Addition und Stringkonkatention zuständig ist.

»»

Setzt er wirklich keinen Hint, oder ist der Hint vielleicht Number?

Warum ist der Hint „Number“ default? Ich habe keine Ahnung. Ich vermute höchstens, dass toString() zu speziell für die meisten Anwendungen von ToPrimitive ist.

Genau hier fehlt mit eine eindeutige Vorgehensweise.

b. alert(o1);
b. Wie ich denke "o"

Was passiert dagegen hier? alert() ist nicht von ECMAScript spezifiziert, deswegen kann ich nur raten. Allerdings ist es offensichtlich, dass alert() den enthaltenen Ausdruck in einen String umwandeln muss.

Ja. Soweit ich weiß, erwartet alert() auch selbst schon einen String, wobei ein anderer Wert notfalls umgewandelt wird.

In einem expliziten String-Kontext wird also durchaus toString() aufgerufen.

Und genau den würde ich für

"Das Objekt " + o1

erwarten.

o1 + o1 ist hingegen nicht eindeutig (bzw. überhaupt nicht) als ein Stringkontext zu sehen. Deswegen wäre hier valueOf() korrekt.

c. alert(o1 + o1);
c. Ich erwarte 2: trifft zu.

Hm? In welchem Browser hast Du getestet? In Spidermonkey, dem Mozilla-JS-Interpreter, kriege ich als Ausgabe "11" wie es auch die Spezifikation vermuten lässt. Oder hast Du oben einen Tippfehler gemacht und Dein o.prototype.valueOf() soll gar keinen String ("1") zurückgeben, sondern eine Zahl (1)?

Du hast recht, war mein Fehler. Ich bitte um Entschuldigung. Richtig wäre return 1 gewesen.