In Javascript hat jedes Objekt eine valueOf () - und eine toString () -Methode. Ich hätte gedacht, dass die toString () -Methode immer dann aufgerufen wird, wenn eine Zeichenfolgenkonvertierung erforderlich ist, aber anscheinend wird sie von valueOf () übertrumpft.
Zum Beispiel der Code
var x = {toString: function() {return "foo"; },
valueOf: function() {return 42; }};
window.console.log ("x="+x);
window.console.log ("x="+x.toString());
wird gedruckt
x=42
x=foo
Das kommt mir rückwärts vor. Wenn x zum Beispiel eine komplexe Zahl wäre, würde ich wollen, dass valueOf () mir seine Größe gibt, aber wann immer ich in einen String konvertieren wollte, würde ich so etwas wie "a + bi" wollen. Und ich möchte nicht explizit toString () in Kontexten aufrufen müssen, die eine Zeichenfolge implizieren.
Ist das so wie es ist?
javascript
Brainjam
quelle
quelle
window.console.log (x);
oderalert (x);
?alert(x)
Anzeigenfoo
undwindow.console.log(x)
Anzeigen angezeigtObject { toString: x.toString(), valueOf: x.valueOf() }
.Antworten:
Der Grund, warum ("x =" + x) "x = Wert" und nicht "x = Zeichenfolge" ergibt, ist der folgende. Bei der Auswertung von "+" sammelt Javascript zuerst die Grundwerte der Operanden und entscheidet dann basierend auf dem Typ jedes Grundelements, ob Addition oder Verkettung angewendet werden soll.
So denkst du, funktioniert es
und genau das passiert tatsächlich
Das heißt, toString wird auf das Ergebnis von valueOf angewendet, nicht auf Ihr ursprüngliches Objekt.
Weitere Informationen finden Sie in Abschnitt 11.6.1 Der Additionsoperator (+) in der ECMAScript-Sprachspezifikation.
* Wenn in String - Kontext genannt, ToPrimitive tut invoke toString, aber das ist hier nicht der Fall, weil ‚+‘ erzwingt keine Art Kontext.
quelle
Hier ist ein bisschen mehr Detail, bevor ich zur Antwort komme:
Die
toString
Funktion wird von nicht "übertrumpft"valueOf
im Allgemeinen . Der ECMAScript-Standard beantwortet diese Frage tatsächlich ziemlich gut. Jedes Objekt verfügt über eine[[DefaultValue]]
Eigenschaft, die bei Bedarf berechnet wird. Wenn der Interpreter nach dieser Eigenschaft fragt, gibt er auch einen "Hinweis" darauf, welche Art von Wert er erwartet. Wenn der Hinweis lautetString
,toString
wird er zuvor verwendetvalueOf
. Wenn der Hinweis jedoch lautetNumber
,valueOf
wird er zuerst verwendet. Beachten Sie, dass, wenn nur eines vorhanden ist oder ein nicht primitives Element zurückgegeben wird, normalerweise das andere als zweite Wahl aufgerufen wird.Das
+
Operator gibt immer den Hinweis ausNumber
, auch wenn der erste Operand ein Zeichenfolgenwert ist. Obwohl es nachx
seinerNumber
Darstellung fragt[[DefaultValue]]
, führt es eine Zeichenfolgenverkettung durch , da der erste Operand eine Zeichenfolge von zurückgibt .Wenn Sie sicherstellen möchten, dass
toString
die Zeichenfolgenverkettung aufgerufen wird, verwenden Sie ein Array und die.join("")
Methode.(ActionScript 3.0 ändert das Verhalten von
+
jedoch geringfügig . Wenn einer der Operanden a istString
, wird er als Zeichenfolgenverkettungsoperator behandelt undString
beim Aufrufen der Hinweis verwendet[[DefaultValue]]
. In AS3 ergibt dieses Beispiel also "foo, x = foo, foo" = x, foo1, 43, x = foo ".)quelle
valueOf
odertoString
Rückkehr nicht-Primitiven, sie werden ignoriert. Wenn keines existiert oder keines ein Grundelement zurückgibt,TypeError
wird a geworfen.[[DefaultValue]](no-hint)
, was äquivalent zu ist[[DefaultValue]](number)
.("" + new Date(0)) === new Date(0).toString()
. Ein Date-Objekt scheint immer seinentoString()
Wert zurückzugeben, wenn es zu etwas hinzugefügt wird.TLDR
Typzwang oder implizite Typkonvertierung ermöglicht eine schwache Typisierung und wird in JavaScript verwendet. Die meisten Operatoren (mit Ausnahme der strengen Gleichheitsoperatoren
===
und!==
) und Wertprüfungsoperationen (z. B.if(value)...
) erzwingen die ihnen zugewiesenen Werte, wenn die Typen dieser Werte nicht sofort mit der Operation kompatibel sind.Der genaue Mechanismus zum Erzwingen eines Werts hängt vom zu bewertenden Ausdruck ab. In der Frage wird der Additionsoperator verwendet.
Der Additionsoperator stellt zunächst sicher, dass beide Operanden Grundelemente sind. In diesem Fall wird die
valueOf
Methode aufgerufen. DietoString
Methode wird in diesem Fall nicht aufgerufen, da die überschriebenevalueOf
Methode für das Objektx
einen primitiven Wert zurückgibt.Da einer der Operanden in der Frage eine Zeichenfolge ist, werden beide Operanden in Zeichenfolgen konvertiert. Dieser Prozess verwendet die abstrakte interne Operation
ToString
(Anmerkung: groß geschrieben) und unterscheidet sich von dertoString
Methode für das Objekt (oder seine Prototypkette).Schließlich werden die resultierenden Zeichenfolgen verkettet.
Einzelheiten
Auf dem Prototyp jedes Konstruktorfunktionsobjekts, das jedem Sprachtyp in JavaScript entspricht (dh Number, BigInt, String, Boolean, Symbol und Object), gibt es zwei Methoden:
valueOf
undtoString
.Der Zweck von
valueOf
besteht darin, den primitiven Wert abzurufen, der einem Objekt zugeordnet ist (falls vorhanden). Wenn einem Objekt kein primitiver Wert zugrunde liegt, wird das Objekt einfach zurückgegeben.Wenn
valueOf
es für ein Grundelement aufgerufen wird, wird das Grundelement auf normale Weise automatisch eingerahmt und der zugrunde liegende Grundelementwert zurückgegeben. Beachten Sie, dass für Zeichenfolgen der zugrunde liegende Grundwert (dh der von zurückgegebene WertvalueOf
) die Zeichenfolgendarstellung selbst ist.Der folgende Code zeigt, dass die
valueOf
Methode den zugrunde liegenden Grundwert von einem Wrapper-Objekt zurückgibt, und es zeigt, wie unveränderte Objektinstanzen, die nicht Grundelementen entsprechen, keinen Grundwert zurückgeben können, sodass sie sich einfach selbst zurückgeben.Der Zweck von
toString
ist andererseits die Rückgabe einer Zeichenfolgendarstellung eines Objekts.Beispielsweise:
Bei den meisten Vorgängen versucht JavaScript stillschweigend, einen oder mehrere Operanden in den erforderlichen Typ zu konvertieren. Dieses Verhalten wurde gewählt, um die Verwendung von JavaScript zu vereinfachen. JavaScript hatte anfangs keine Ausnahmen , und dies könnte auch bei dieser Entwurfsentscheidung eine Rolle gespielt haben. Diese Art der impliziten Typkonvertierung wird als Typenzwang bezeichnet und ist die Grundlage für das lose (schwache) JavaScript-Typsystem. Die komplizierten Regeln hinter diesem Verhalten sollen die Komplexität der Typisierung in die Sprache selbst und aus Ihrem Code heraus verschieben.
Während des Zwangsprozesses können zwei Arten der Umwandlung auftreten:
Number()
,Boolean()
,String()
Etc.)Umwandlung in ein Primitiv
Beim Versuch, nicht-primitive Typen in zu bearbeitende Primitive zu konvertieren, wird die abstrakte Operation
ToPrimitive
mit einem optionalen "Hinweis" auf "Zahl" oder "Zeichenfolge" aufgerufen. Wenn der Hinweis weggelassen wird, lautet der Standardhinweis 'number' (es sei denn, die@@toPrimitive
Methode wurde überschrieben). Wenn der Hinweis 'string' ist,toString
wird zuerst versucht, undvalueOf
zweitens, wenntoString
kein Grundelement zurückgegeben wurde. Sonst umgekehrt. Der Hinweis hängt von der Operation ab, die die Konvertierung anfordert.Der Additionsoperator liefert keinen Hinweis, wird also
valueOf
zuerst versucht. Der Subtraktionsoperator gibt einen Hinweis auf 'Zahl' aus, wird alsovalueOf
zuerst versucht. Die einzigen Situationen, die ich in der Spezifikation finden kann, in denen der Hinweis "Zeichenfolge" ist, sind:Object#toString
ToPropertyKey
, die ein Argument in einen Wert konvertiert, der als Eigenschaftsschlüssel verwendet werden kannDirekte Typkonvertierung
Jeder Bediener hat seine eigenen Regeln für den Abschluss seines Vorgangs. Der Additionsoperator stellt zunächst
ToPrimitive
sicher, dass jeder Operand ein Grundelement ist. Wenn einer der Operanden eine Zeichenfolge ist, ruft er absichtlich die abstrakte OperationToString
für jeden Operanden auf, um das erwartete Verkettungsverhalten der Zeichenfolge mit Zeichenfolgen zu erzielen. Wenn nach demToPrimitive
Schritt beide Operanden keine Zeichenfolgen sind, wird eine arithmetische Addition durchgeführt.Im Gegensatz zur Addition hat der Subtraktionsoperator kein überladenes Verhalten und ruft daher
toNumeric
jeden Operanden auf, der sie zuerst mit in Primitive konvertiert hatToPrimitive
.So:
Beachten Sie, dass das
Date
intrinsische Objekt eindeutig ist, da es das einzige intrinsische Objekt ist,@@toPrimitive
das die Standardmethode überschreibt , bei der angenommen wird, dass der Standardhinweis "Zeichenfolge" (anstelle von "Zahl") ist. Der Grund dafür ist, dassDate
Instanzen zur Vereinfachung für den Programmierer standardmäßig anstelle ihres numerischen Werts in lesbare Zeichenfolgen übersetzt werden. Sie können@@toPrimitive
Ihre eigenen Objekte mit überschreibenSymbol.toPrimitive
.Das folgende Raster zeigt die Zwangsergebnisse für den abstrakten Gleichheitsoperator (
==
) ( Quelle ):Siehe auch .
quelle