Ein kürzlich veröffentlichter Tweet enthielt diesen Ausschnitt aus JavaScript.
Kann jemand bitte Schritt für Schritt erklären, was darin passiert?
> function dis() { return this }
undefined
> five = dis.call(5)
Number {[[PrimitiveValue]]: 5}
> five.wtf = 'potato'
"potato"
> five.wtf
"potato"
> five * 5
25
> five.wtf
"potato"
> five++
5
> five.wtf
undefined
> five.wtf = 'potato?'
"potato?"
> five.wtf
undefined
> five
6
Insbesondere ist mir nicht klar:
- warum das Ergebnis von
dis.call(5)
aNumber
mit einer Art[[PrimitiveValue]]
Eigenschaft ist, aber die Ergebnisse vonfive++
undfive * 5
scheinen nur die einfachen Zahlen5
und25
(nichtNumber
s) zu sein - warum die
five.wtf
Eigenschaft nach demfive++
Inkrement verschwindet - warum die
five.wtf
Eigenschaft nach demfive++
Inkrement nicht mehr einstellbar ist , obwohl diefive.wtf = 'potato?'
Zuordnung anscheinend den Wert festlegt.
javascript
Nathan Long
quelle
quelle
++
scheint aber den zugrunde liegenden Typ zu beeinflussenPre
vsPost
Inkrement? Nach der Multiplikation ist es wieder einNumber
Objekt, das keinewtf
Eigenschaft hat ... Aber es ist immer noch einobject
daher kann es habenproperties
..dis
mitdis.call(5)
, Wraps dies die primitive Zahl5
in ein Objekt vom TypNumber
, der das enthält5
, so dass dieses Objekt als zurückgegeben werden kannthis
Objekt. Das++
konvertiert es zurück in eine primitive Zahl, die keine Eigenschaften enthalten kann, alsowtf
beginnt es undefiniert zu sein.Antworten:
OP hier. Lustig, dies auf Stack Overflow zu sehen :)
Bevor Sie das Verhalten durchgehen, ist es wichtig, einige Dinge zu klären:
Zahlenwert und Zahlenobjekt (
a = 3
vsa = new Number(3)
) sind sehr unterschiedlich. Einer ist ein Primitiv, der andere ist ein Objekt. Sie können Grundelementen keine Attribute zuweisen, Objekte jedoch.Zwang zwischen den beiden ist implizit.
Beispielsweise:
Jeder Ausdruck hat einen Rückgabewert. Wenn die REPL einen Ausdruck liest und ausführt, wird dies angezeigt. Die Rückgabewerte bedeuten oft nicht, was Sie denken, und implizieren Dinge, die einfach nicht wahr sind.
Ok, los geht's.
Das Versprechen.
Definieren Sie eine Funktion
dis
und rufen Sie sie mit auf5
. Dadurch wird die Funktion mit5
als Kontext (this
) ausgeführt. Hier wird es von einem Zahlenwert zu einem Zahlenobjekt gezwungen. Es ist sehr wichtig zu beachten, dass dies nicht geschehen wäre, wenn wir uns im strengen Modus befunden hätten .Jetzt setzen wir das Attribut
five.wtf
auf'potato'
und mit fünf als Objekt, sicher genug, dass es die einfache Zuweisung akzeptiert .Mit
five
als Objekt stelle ich sicher, dass es immer noch einfache arithmetische Operationen ausführen kann. Es kann. Bleiben seine Eigenschaften noch bestehen? Ja.Die Wende.
Jetzt überprüfen wir
five++
. Der Trick beim Postfix-Inkrementieren besteht darin, dass der gesamte Ausdruck anhand des ursprünglichen Werts ausgewertet und dann den Wert erhöht wird. Es sieht aus wiefive
noch fünf, aber wirklich der Ausdruck auf fünf ausgewertet, dann eingestelltfive
zu6
.Es wurde nicht nur
five
auf gesetzt6
, sondern es wurde zurück in einen Zahlenwert gezwungen, und alle Attribute gehen verloren. Da Grundelemente keine Attribute enthalten können,five.wtf
ist sie undefiniert.Ich versuche , wieder ein Attribut zuweisen
wtf
zufive
. Der Rückgabewert impliziert, dass er haftet, aber tatsächlich nicht, weilfive
es sich um einen Zahlenwert handelt, nicht um ein Zahlenobjekt. Der Ausdruck wird ausgewertet'potato?'
, aber wenn wir überprüfen, sehen wir, dass er nicht zugewiesen wurde.Das Prestige.
Seit dem Postfix-Inkrement
five
ist6
.quelle
int
undInteger
zum Beispiel. Ich gehe davon aus, dass Sie auf diese Weise eine Funktion erstellendoSomething(Object)
und ihr dennoch Primitive geben können. In diesem Fall werden Grundelemente in die entsprechenden Klassen konvertiert. Aber JS kümmert sich nicht wirklich um Typen, also ist der Grund wahrscheinlich etwas anderes++
wenden Sie ToNumber auf den Wert an . Vergleichen Sie einen ähnlichen Fall mit Zeichenfolgen: Wenn jax="5"
, wirdx++
die Zahl zurückgegeben5
.dis.call(5)
, der Zwang, Einwände zu erheben, das hätte ich nie erwartet.Es gibt zwei verschiedene Möglichkeiten, eine Zahl darzustellen:
Das erste ist ein Primitiv, das zweite ein Objekt. In jeder Hinsicht verhalten sich beide gleich, außer dass sie beim Drucken auf der Konsole unterschiedlich aussehen. Ein wichtiger Unterschied besteht darin, dass ein Objekt
new Number(5)
wie jede Ebene neue Eigenschaften akzeptiert{}
, während das Grundelement5
dies nicht tut:Informationen zum ersten
dis.call(5)
Teil finden Sie unter Wie funktioniert das Schlüsselwort "this"? . Sagen wir einfach, dass das erste Argument tocall
als Wert von verwendetthis
wird und dass diese Operation die Zahl in die komplexereNumber
Objektform++
zwingt . * Später zwingt sie sie zurück in die primitive Form, da die Additionsoperation+
zu einem neuen Primitiv führt.Ein
Number
Objekt akzeptiert neue Eigenschaften.++
ergibt einen neuen primitiven6
Wert ...... die keine benutzerdefinierten Attribute haben und nicht akzeptieren.
* Beachten Sie, dass im strengen Modus das
this
Argument anders behandelt und nicht in a konvertiert wirdNumber
. Einzelheiten zur Implementierung finden Sie unter http://es5.github.io/#x10.4.3 .quelle
#define true false
. Oder in Java, wo Sie einfach neu definieren können, was Zahlen bedeuten. Das sind gute feste Sprachen. In Wahrheit hat jede Sprache ähnliche "Tricks", bei denen Sie ein Ergebnis erhalten, das wie beabsichtigt funktioniert, aber seltsam aussehen kann.In der JavaScript-Welt gibt es Zwang - eine Detektivgeschichte
Nathan, du hast keine Ahnung, was du entdeckt hast.
Ich habe das jetzt seit Wochen untersucht. Alles begann in einer stürmischen Nacht im letzten Oktober. Ich bin versehentlich auf die
Number
Klasse gestoßen - ich meine, warum in aller Welt hatte JavaScript eineNumber
Klasse?Ich war nicht auf das vorbereitet, was ich als nächstes herausfinden würde.
Es stellt sich heraus, dass JavaScript, ohne es Ihnen mitzuteilen, Ihre Zahlen in Objekte und Ihre Objekte in Zahlen direkt unter Ihrer Nase geändert hat.
JavaScript hatte gehofft, niemand würde es verstehen, aber die Leute haben seltsames unerwartetes Verhalten gemeldet, und jetzt habe ich dank Ihnen und Ihrer Frage die Beweise, die ich brauche, um dieses Ding weit aufzublasen.
Das haben wir bisher herausgefunden. Ich weiß nicht, ob ich Ihnen das überhaupt sagen soll - vielleicht möchten Sie Ihr JavaScript ausschalten.
Als Sie diese Funktion erstellt haben, hatten Sie wahrscheinlich keine Ahnung, was als nächstes passieren würde. Alles sah gut aus und alles war gut - für jetzt.
Keine Fehlermeldungen, nur das Wort "undefiniert" in der Konsolenausgabe, genau das, was Sie erwarten würden. Immerhin war dies eine Funktionsdeklaration - sie soll nichts zurückgeben.
Dies war jedoch nur der Anfang. Was als nächstes geschah, konnte niemand vorhersagen.
Ja, ich weiß, du hast ein erwartet
5
, aber das hast du nicht, war es - du hast etwas anderes - etwas anderes.Mir geht es genauso.
Ich wusste nicht, was ich davon halten sollte. Es hat mich verrückt gemacht. Ich konnte nicht schlafen, ich konnte nicht essen, ich versuchte es wegzutrinken, aber keine Menge Gebirgstau würde mich vergessen lassen. Es ergab einfach keinen Sinn!
Da fand ich heraus, was wirklich los war - es war Zwang, und es geschah genau dort vor meinen Augen, aber ich war zu blind, um es zu sehen.
Mozilla versuchte es zu begraben, indem sie es dort platzierte, wo sie wussten, dass niemand hinschauen würde - in ihrer Dokumentation .
Nach Stunden des rekursiven Lesens und erneuten Lesens und erneuten Lesens fand ich Folgendes:
Es war genau dort klar, wie in Open Sans-Schrift geschrieben werden kann. Es war die
call()
Funktion - wie konnte ich so dumm sein?!Meine Nummer war überhaupt keine Nummer mehr. In dem Moment, als ich es weitergab
call()
, wurde es etwas anderes. Es wurde ... ein Objekt.Ich konnte es zuerst nicht glauben. Wie könnte das wahr sein? Aber ich konnte die Beweise, die sich um mich herum häuften, nicht ignorieren. Es ist genau dort, wenn Sie nur schauen:
wtf
hatte Recht. Zahlen können keine benutzerdefinierten Eigenschaften haben - das wissen wir alle! Es ist das erste, was sie dir an der Akademie beibringen.Wir hätten es wissen müssen, als wir die Konsolenausgabe sahen - dies war nicht die Zahl, die wir dachten. Dies war ein Betrüger - ein Gegenstand, der sich als unsere süße unschuldige Zahl ausgibt.
Das war ...
new Number(5)
.Natürlich! Es machte vollkommen Sinn.
call()
hatte einen Job zu erledigen, er musste eine Funktion aufrufen, und um das zu tun, musste er füllenthis
, er wusste, dass er das nicht mit einer Nummer machen konnte - er brauchte ein Objekt und er war bereit, alles zu tun, um es zu bekommen, sogar wenn das bedeutete, unsere Nummer zu zwingen. Als ercall()
die Nummer5
sah, sah er eine Gelegenheit.Es war der perfekte Plan: Warten Sie, bis niemand mehr hinschaut, und tauschen Sie unsere Nummer gegen ein Objekt aus, das genauso aussieht. Wir bekommen eine Nummer, die Funktion wird aufgerufen und niemand wäre klüger.
Es war wirklich der perfekte Plan, aber wie bei allen Plänen, auch bei den perfekten, war ein Loch darin, und wir wollten gleich hineinfallen.
Sehen Sie, was
call()
nicht verstanden wurde, war, dass er nicht der einzige in der Stadt war, der Zahlen erzwingen konnte. Das war schließlich JavaScript - Zwang war überall.call()
Ich nahm meine Nummer und wollte nicht aufhören, bis ich die Maske von seinem kleinen Betrüger abzog und ihn der gesamten Stack Overflow-Community aussetzte.Aber wie? Ich brauchte einen Plan. Sicher, es sieht aus wie eine Zahl, aber ich weiß, dass es nicht so ist. Es muss einen Weg geben, das zu beweisen. Das ist es! Es sieht aus wie eine Zahl, aber kann es sich wie eine verhalten?
Ich sagte,
five
ich brauche ihn, um fünfmal größer zu werden - er fragte nicht warum und ich erklärte es nicht. Ich habe dann getan, was jeder gute Programmierer tun würde: Ich habe multipliziert. Sicherlich konnte er sich hier nicht vortäuschen.Verdammt! Nicht nur gut
five
multiplizierenwtf
war noch da. Verdammt dieser Typ und seine Kartoffel.Was zur Hölle war los? War ich in dieser ganzen Sache falsch? Ist das
five
wirklich eine Nummer? Nein, ich muss etwas vermissen, ich weiß es, es gibt etwas, das ich vergessen muss, etwas so Einfaches und Grundlegendes, dass ich es völlig übersehen habe.Das sah nicht gut aus, ich hatte diese Antwort stundenlang geschrieben und war immer noch nicht näher dran, meinen Standpunkt zu vertreten. Ich konnte nicht so weitermachen, irgendwann hörten die Leute auf zu lesen, ich musste an etwas denken und ich musste schnell daran denken.
Warten Sie, das ist es!
five
war nicht 25, 25 war das Ergebnis, 25 war eine ganz andere Zahl. Natürlich, wie könnte ich das vergessen? Zahlen sind unveränderlich. Wenn Sie multiplizieren, wird5 * 5
nichts zugewiesen. Sie erstellen einfach eine neue Zahl25
.Das muss hier passieren. Irgendwie , wenn ich mehrfach
five * 5
,five
muss immer in eine Reihe gezwungen und diese Zahl muss der eine für die Multiplikation verwendet werden. Es sind die Ergebnisse dieser Multiplikation, die auf der Konsole gedruckt werden, nicht der Wert von sichfive
selbst.five
bekommt nie etwas zugewiesen - also ändert es sich natürlich nicht.Wie kann ich mir dann
five
das Ergebnis einer Operation zuordnen? Ich habe es verstanden. Bevorfive
ich überhaupt nachdenken konnte, schrie ich "++".Aha! Ich hatte ihn! Jeder weiß ,
5 + 1
ist6
, war dies der Beweis Ich musste, dass erfive
keine Zahl war! Es war ein Betrüger! Ein schlechter Betrüger, der nicht zählen konnte. Und ich könnte es beweisen. So verhält sich eine reelle Zahl:Warten? Was war hier los? seufz Ich war so in das Busting verwickelt,
five
dass ich vergesse, wie Postbetreiber arbeiten. Wenn ich++
am Ende vonfive
sage, gebe ich den aktuellen Wert zurück und erhöhe ihn dannfive
. Es ist der Wert vor dem Vorgang, der auf der Konsole gedruckt wird.num
war in der Tat6
und ich konnte es beweisen:Zeit zu sehen, was
five
wirklich war:... es war genau das, was es sein sollte.
five
war gut - aber ich war besser. Wennfive
es immer noch ein Objekt wäre, würde das bedeuten, dass es immer noch das Eigentum hättewtf
und ich wäre bereit, alles zu wetten, was es nicht tat.Aha! Ich lag richtig. Ich hatte ihn!
five
war jetzt eine Nummer - es war kein Objekt mehr. Ich wusste, dass der Multiplikationstrick es diesmal nicht retten würde. Sehenfive++
ist wirklichfive = five + 1
. Im Gegensatz zur Multiplikation weist der++
Operator einen Wert zufive
. Insbesondere weist es ihm die Ergebnisse zu, vonfive + 1
denen genau wie im Fall der Multiplikation eine neue unveränderliche Zahl zurückgegeben wird .Ich wusste, dass ich ihn hatte und nur um sicherzugehen, dass er sich nicht herauswinden konnte. Ich hatte noch einen Test im Ärmel. Wenn ich recht hätte und
five
jetzt wirklich eine Nummer wäre, würde das nicht funktionieren:Diesmal würde er mich nicht täuschen. Ich wusste
potato?
, dass es auf der Konsole gedruckt werden würde, da dies die Ausgabe der Aufgabe ist. Die eigentliche Frage ist, wird eswtf
noch da sein?Genau wie ich vermutet habe - nichts - weil Nummern keine Eigenschaften zugewiesen werden können. Das haben wir im ersten Jahr an der Akademie gelernt;)
Danke Nathan. Dank Ihres Mutes, diese Frage zu stellen, kann ich das alles endlich hinter mich bringen und zu einem neuen Fall übergehen.
Wie dieser über die Funktion
toValue()
. Oh mein Gott. Nein!quelle
01
deklariert eine Funktiondis
, die das Kontextobjekt zurückgibt. Wasthis
Änderungen darstellt, hängt davon ab, ob Sie den strengen Modus verwenden oder nicht. Das gesamte Beispiel hat unterschiedliche Ergebnisse, wenn die Funktion wie folgt deklariert wurde:Dies wird in Abschnitt 10.4.3 in der ES5-Spezifikation beschrieben
02
ist der Rückgabewert der Funktionsdeklaration.undefined
sollte hier selbsterklärend sein.03
Die Variablefive
wird mit dem Rückgabewert initialisiert,dis
wenn sie im Kontext des primitiven Werts aufgerufen wird5
. Dadis
sich diese Leitung nicht im strengen Modus befindet, ist sie mit dem Anrufen identischfive = Object(5)
.04
Der ungeradeNumber {[[PrimitiveValue]]: 5}
Rückgabewert ist die Darstellung des Objekts, das den primitiven Wert umschließt5
05
five
Derwtf
Eigenschaft des Objekts wird ein Zeichenfolgenwert von zugewiesen'potato'
06
ist der Rückgabewert der Zuordnung und sollte selbsterklärend sein.07
five
Diewtf
Eigenschaft des Objekts wird untersucht08
wiefive.wtf
zuvor eingestellt,'potato'
kehrt es'potato'
hier zurück09
Dasfive
Objekt wird mit dem Grundwert multipliziert5
. Dies unterscheidet sich nicht von anderen Objekten, die multipliziert werden, und wird in Abschnitt 11.5 der ES5-Spezifikation erläutert . Besonders hervorzuheben ist, wie Objekte in numerische Werte umgewandelt werden, was in einigen Abschnitten behandelt wird.9.3 ToNumber :
9.1 ToPrimitive :
8.12.8 [[DefaultValue]] :
Dies ist alles ein Umweg, um zu sagen, dass die
valueOf
Funktion des Objekts aufgerufen wird und der Rückgabewert dieser Funktion in der Gleichung verwendet wird. Wenn Sie dievalueOf
Funktion ändern, können Sie die Ergebnisse der Operation ändern:10
wiefive
svalueOf
Funktion war unverändert, es gibt den eingewickelt Grundwert ,5
so dassfive * 5
auswertet zu5 * 5
denen Ergebnisse in25
11
five
Diewtf
Eigenschaft des Objekts wird erneut ausgewertet , obwohl sie seit ihrer Zuweisung unverändert geblieben ist05
.12
'potato'
13
Der Postfix Increment Operator wird aufgerufen. Er ruftfive
den numerischen Wert ab (5
wir haben bereits erläutert, wie früher), speichert den Wert, damit er zurückgegeben werden kann, addiert ihn1
zum Wert (6
), weist den Wert zufive
und gibt den gespeicherten Wert zurück (5
)14
Nach wie vor ist der zurückgegebene Wert der Wert, bevor er erhöht wurde15
Auf diewtf
Eigenschaft des6
in der Variablen gespeicherten primitiven Werts ( )five
wird zugegriffen. Abschnitt 15.7.5 der ES5-Spezifikation definiert dieses Verhalten. Zahlen erhalten die Eigenschaften vonNumber.prototype
.16
Number.prototype
hat keinewtf
Eigenschaft, wird alsoundefined
zurückgegeben17
five.wtf
wird ein Wert von zugewiesen'potato?'
. Die Zuordnung ist in 11.13.1 der ES5-Spezifikation definiert . Grundsätzlich wird der zugewiesene Wert zurückgegeben, aber nicht gespeichert.18
'potato?'
wurde vom Zuweisungsoperator zurückgegeben19
Auch hierfive
wird auf den Wert von6
zugegriffen, und es wird erneutNumber.prototype
keinewtf
Eigenschaft angegeben20
undefined
wie oben erklärt21
five
wird zugegriffen22
6
wird wie in erklärt zurückgegeben13
quelle
Es ist ziemlich einfach.
Dies gibt den
this
Kontext zurück. Wenn Sie dies tun, übergebencall(5)
Sie die Nummer als Objekt.Die
call
Funktion liefert keine Argumente. Das erste Argument, das Sie angeben, ist der Kontext vonthis
. Wenn Sie es im Kontext haben möchten, geben Sie es normalerweise{}
so andis.call({})
, was bedeutet, dassthis
die Funktion leer istthis
. Wenn Sie jedoch bestehen, wird5
es anscheinend in ein Objekt konvertiert. Siehe .callDie Rückkehr ist also
object
Wenn Sie dies tun
five * 5
, sieht JavaScript das Objektfive
als primitiven Typ und ist daher äquivalent zu5 * 5
. Interessanterweise ist'5' * 5
es immer noch gleich25
, so dass JavaScript eindeutig unter die Haube wirft. Infive
dieser Zeile werden keine Änderungen am zugrunde liegenden Typ vorgenommenWenn Sie dies
++
jedoch tun , wird das Objekt in den primitivennumber
Typ konvertiert, wodurch die.wtf
Eigenschaft entfernt wird. Weil Sie den zugrunde liegenden Typ beeinflussenquelle
++
konvertiert und weist es zurück.++
ist gleichvariable = variable + 1
. Sie verlieren alsowtf
*
vs++
verwirrt mich überhaupt nicht. Eine Funktion zu haben, die keine Argumente erwartet und zurückgibtthis
, diese Funktion trotzdem ein Argument akzeptieren zu lassen und etwas zurückzugeben, das dem Argument ähnelt, aber nicht genau ist - das macht für mich keinen Sinn.dis.call()
funktioniert.this
ist einfach ein Zeiger auf ein Objekt, sodass primitive Typen implizit konvertiert werden. Warum konnte eine Funktion ohne Argumente nicht mindestens einen Kontext haben? Das erste Argument voncall
oderbind
wird verwendet, um den Kontext festzulegen. Außerdem sind Funktionen Schließungen, was bedeutet, dass sie Zugriff auf mehr als nurarguments
Die primitiven Werte können keine Eigenschaft haben. Wenn Sie jedoch versuchen, auf eine Eigenschaft mit primitivem Wert zuzugreifen, wird sie transparent in ein temporäres Number-Objekt umgewandelt.
So:
quelle
Funktion deklarieren
dis
. Die Funktion gibt ihren Kontext zurückdis
Mit Kontext anrufen5
. Primitive Werte werden eingerahmt, wenn sie im strengen Modus ( MDN ) als Kontext übergeben werden . Alsofive
jetzt ist Objekt (Boxnummer).Deklarieren Sie die
wtf
Eigenschaft für diefive
VariableWert von
five.wtf
five
ist eingerahmt5
, also ist es Nummer und Objekt gleichzeitig (5 * 5 = 25). Es ändert sich nichtfive
.Wert von
five.wtf
Hier auspacken
five
.five
jetzt ist nur primitivnumber
. Er druckt5
, und fügen Sie dann1
zufive
.five
ist6
jetzt primitive Zahl , es gibt keine Eigenschaften darin.Grundelemente können keine Eigenschaften haben, Sie können dies nicht festlegen
Sie können dies nicht lesen, da es nicht eingestellt wurde
five
liegt an6
der obigen Inkrementierung des Beitragsquelle
Zunächst sieht es so aus, als würde dies über die NodeJS-Konsole ausgeführt.
1.
Erstellt die Funktion dis (), aber da sie nicht als a festgelegt wurde,
var
gab es keinen Wert, der zurückgegeben werden konnte, ebensoundefined
wie die Ausgabe, obwohl siedis()
definiert wurde. Auf einer Nebenbemerkungthis
wurde nicht zurückgegeben, weil die Funktion nicht ausgeführt wurde.2.
Diese kehrt Javascript ist
Number
Objekt , weil Sie nur die Funktion einstellendis()
‚sthis
Wert auf den ursprünglichen fünf.3.
Der erste kehrt zurück,
"potato"
weil Sie gerade die Eigenschaftwtf
vonfive
auf gesetzt haben'potato'
. Javascript gibt den Wert einer von Ihnen festgelegten Variablen zurück, sodass Sie auf einfache Weise mehrere Variablen verketten und auf denselben Wert wie folgt setzen können :a = b = c = 2
.4.
Dies gibt ,
25
weil Sie multipliziert einfach die primitive Zahl5
zufive
. Der Wert vonfive
wurde durch den Wert desNumber
Objekts bestimmt.5.
Ich habe diese Zeile zuvor übersprungen, weil ich sie hier wiederholen würde. Es wird nur der Wert der Eigenschaft zurückgegeben
wtf
, die Sie oben festgelegt haben.6.
Wie @Callum sagte,
++
wird der Typnumber
vom Objekt in denselben Wert konvertiertNumber {[[PrimitiveValue]]: 5}}
.Jetzt, weil
five
es a istnumber
, können Sie keine Eigenschaften mehr festlegen, bis Sie so etwas tun:oder
Beachten Sie auch, dass der zweite Weg ein anderes Verhalten aufweist als die erste Methode, da anstelle des
Number
zuvor erstellten Objekts ein generisches Objekt definiert wird .Ich hoffe, das hilft, Javascript nimmt gerne Dinge an, so dass es verwirrend werden kann, wenn man vom
Number
Objekt zum Grundelement wechseltnumber
. Sie können überprüfen, um welchen Typ es sich handelt, indem Sie dastypeof
Schlüsselwort verwenden. Geben Sie den Typ 5 ein, nachdem Sie ihn initialisiert haben'object'
, und nachdem Siefive++
ihn zurückgegeben haben'number'
.@deceze beschreibt den Unterschied zwischen dem Number-Objekt und der primitiven Zahl sehr gut.
quelle
JavaScript-Bereiche bestehen aus Ausführungskontexten. Jeder Ausführungskontext verfügt über eine lexikalische Umgebung (externe / global begrenzte Werte), eine variable Umgebung (lokal begrenzte Werte) und eine diese Bindung .
Die diese Bindung ist ein sehr wichtiger Teil des Ausführungskontextes. Die Verwendung
call
ist eine Möglichkeit, diese Bindung zu ändern. Dadurch wird automatisch ein Objekt erstellt, mit dem die Bindung gefüllt wird.Function.prototype.call () (von MDN)
Sobald es offensichtlich ist, dass 5 in umgewandelt wird
new Number(5)
, sollte der Rest ziemlich offensichtlich sein. Beachten Sie, dass andere Beispiele ebenfalls funktionieren, solange es sich um primitive Werte handelt.quelle
Einige Konzepte erklären, was passiert
5
ist eine Zahl, ein primitiver WertNumber {[[PrimitiveValue]]: 5}
ist eine Instanz von Number (nennen wir es Object Wrapper)Wenn Sie über einen primitiven Wert auf eine Eigenschaft / Methode zugreifen, erstellt die JS-Engine einen Objekt-Wrapper des entsprechenden Typs (
Number
für5
,String
für'str'
undBoolean
fürtrue
) und löst den Eigenschaftszugriff / Methodenaufruf für diesen Objekt-Wrapper auf. Dies passierttrue.toString()
zum Beispiel , wenn Sie dies tun .Wenn Sie Operationen an Objekten ausführen, werden diese (mit
toString
odervalueOf
) in primitive Werte konvertiert , um diese Operationen aufzulösen - beispielsweise wenn Sie dies tunstring
enthält die Zeichenfolgenverkettung vonmystr
undobj.toString()
und enthältnumber
die Hinzufügung von3
undobj.valueOf()
.Nun, um alles zusammenzufügen
dis.call(5)
verhält sich so, als(5).dis()
hätte man5
tatsächlich die Methodedis
. Um den Methodenaufruf aufzulösen, wird der Objekt-Wrapper erstellt und der Methodenaufruf darauf aufgelöst. Zu diesem Zeitpunkt zeigt fünf auf einen Objekt-Wrapper um den Grundwert 5.Das Festlegen einer Eigenschaft für ein Objekt ist hier nichts Besonderes.
Dadurch wird
five.valueOf() * 5
der primitive Wert tatsächlich vom Objekt-Wrapper abgerufen.five
zeigt immer noch auf das ursprüngliche Objekt.Das ist eigentlich
five = five.valueOf() + 1
. Vor dieser Zeile befindet sichfive
der Objekt-Wrapper um den Wert 5, während nach diesem Punktfive
der primitive Wert enthalten ist6
.five
ist kein Objekt mehr. Jede dieser Zeilen erstellt eine neue Instanz von Number, um den.wtf
Eigenschaftszugriff aufzulösen . Die Instanzen sind unabhängig, sodass das Festlegen einer Eigenschaft für eine Instanz für eine andere nicht sichtbar ist. Der Code entspricht vollständig diesem:quelle