it-swarm.com.de

Warum gibt ++ [[]] [+ []] + [+ []] die Zeichenfolge "10" zurück?

Dies ist gültig und gibt den String "10" in JavaScript zurück ( weitere Beispiele hier ):

console.log(++[[]][+[]]+[+[]])

Warum? Was passiert hier?

1561
JohnJohnGa

Wenn wir es aufteilen, ist das Durcheinander gleich:

++[[]][+[]]
+
[+[]]

In JavaScript ist es wahr, dass +[] === 0. + wandelt etwas in eine Zahl um, und in diesem Fall ergibt sich +"" oder 0 (siehe Spezifikationsdetails unten).

Daher können wir es vereinfachen (++ hat Vorrang vor +):

++[[]][0]
+
[0]

Da [[]][0] bedeutet: Hole das erste Element aus [[]], ist es wahr, dass:

[[]][0] gibt das innere Array zurück ([]). Aufgrund von Referenzen ist es falsch, [[]][0] === [] zu sagen, aber nennen wir das innere Array A, um die falsche Schreibweise zu vermeiden.

++ vor seinem Operanden bedeutet "um eins inkrementieren und das inkrementierte Ergebnis zurückgeben". Also ist ++[[]][0] äquivalent zu Number(A) + 1 (oder +A + 1).

Auch hier können wir das Durcheinander in etwas Lesbareres vereinfachen. Ersetzen wir [] zurück durch A:

(+[] + 1)
+
[0]

Bevor +[] das Array in die Zahl 0 konvertieren kann, muss es zuerst in eine Zeichenfolge konvertiert werden, die wiederum "" ist. Schließlich wird 1 hinzugefügt, was zu 1 führt.

  • (+[] + 1) === (+"" + 1)
  • (+"" + 1) === (0 + 1)
  • (0 + 1) === 1

Vereinfachen wir es noch weiter:

1
+
[0]

Dies gilt auch für JavaScript: [0] == "0", da es ein Array mit einem Element verknüpft. Durch das Verbinden werden die durch , getrennten Elemente verkettet. Mit einem Element können Sie ableiten, dass diese Logik zum ersten Element selbst führt.

In diesem Fall sieht + zwei Operanden: eine Zahl und ein Array. Es wird jetzt versucht, die beiden zu demselben Typ zu zwingen. Zuerst wird das Array in die Zeichenfolge "0" umgewandelt, dann wird die Zahl in eine Zeichenfolge ("1") umgewandelt. Number + String === String.

"1" + "0" === "10" // Yay!

Spezifikationsdetails für +[]:

Dies ist ein ziemliches Labyrinth, aber um +[] zu machen, wird es zuerst in eine Zeichenkette konvertiert, denn das sagt +:

11.4.6 Unär + Operator

Der Operator unary + konvertiert seinen Operanden in den Typ Number.

Die Produktion UnaryExpression: + UnaryExpression wird wie folgt ausgewertet:

  1. Sei expr das Ergebnis der Auswertung von UnaryExpression.

  2. Return ToNumber (GetValue (expr)).

ToNumber() sagt:

Objekt

Wenden Sie die folgenden Schritte an:

  1. PrimValue sei ToPrimitive (Eingabeargument, Hinweiszeichenfolge).

  2. Return ToString (primValue).

ToPrimitive() sagt:

Objekt

Gibt einen Standardwert für das Objekt zurück. Der Standardwert eines Objekts wird durch Aufrufen der internen Methode [[DefaultValue]] des Objekts abgerufen, wobei der optionale Hinweis PreferredType übergeben wird. Das Verhalten der internen Methode [[DefaultValue]] wird in dieser Spezifikation für alle systemeigenen ECMAScript-Objekte in 8.12.8 definiert.

[[DefaultValue]] sagt:

8.12.8 [[DefaultValue]] (Hinweis)

Wenn die interne Methode [[DefaultValue]] von O mit Hinweiszeichenfolge aufgerufen wird, werden die folgenden Schritte ausgeführt:

  1. ToString sei das Ergebnis des Aufrufs der internen Methode [[Get]] von Objekt O mit dem Argument "toString".

  2. Wenn IsCallable (toString) wahr ist,

ein. Es sei str das Ergebnis des Aufrufs der internen Methode [[Call]] von toString, mit O als diesem Wert und einer leeren Argumentliste.

b. Wenn str ein primitiver Wert ist, geben Sie str zurück.

Der .toString eines Arrays lautet:

15.4.4.2 Array.prototype.toString ()

Wenn die toString-Methode aufgerufen wird, werden die folgenden Schritte ausgeführt:

  1. Das Array sei das Ergebnis des Aufrufs von ToObject für diesen Wert.

  2. Sei func das Ergebnis des Aufrufs der internen Methode [[Get]] des Arrays mit dem Argument "join".

  3. Wenn IsCallable (func) false ist, ist func die standardmäßig integrierte Methode Object.prototype.toString (15.2.4.2).

  4. Gibt das Ergebnis des Aufrufs der internen Methode [[Call]] der Funktion zur Bereitstellung eines Arrays als this-Wert und einer leeren Argumentliste zurück.

Also kommt +[] zu +"", weil [].join() === "".

Wieder ist der + wie folgt definiert:

11.4.6 Unär + Operator

Der Operator unary + konvertiert seinen Operanden in den Typ Number.

Die Produktion UnaryExpression: + UnaryExpression wird wie folgt ausgewertet:

  1. Sei expr das Ergebnis der Auswertung von UnaryExpression.

  2. Return ToNumber (GetValue (expr)).

ToNumber ist für "" definiert als:

Das MV von StringNumericLiteral ::: [leer] ist 0.

Also +"" === 0 und damit +[] === 0.

2009
pimvdb
++[[]][+[]] => 1 // [+[]] = [0], ++0 = 1
[+[]] => [0]

Dann haben wir eine String-Verkettung

1+[0].toString() = 10
113
Shef

Das Folgende wurde aus einem blog-Post übernommen, der diese Frage beantwortet, die ich gepostet habe, während diese Frage noch geschlossen war. Links sind (eine HTML-Kopie von) der ECMAScript 3-Spezifikation, die in den heute gebräuchlichen Webbrowsern immer noch die Grundlage für JavaScript darstellt.

Zunächst ein Kommentar: Diese Art von Ausdruck wird in keiner (vernünftigen) Produktionsumgebung auftauchen und ist nur als Übung von Nutzen, wie gut der Leser die schmutzigen Kanten von JavaScript kennt. Das allgemeine Prinzip, dass JavaScript-Operatoren implizit zwischen Typen konvertieren, ist nützlich, wie auch einige der gängigen Konvertierungen. Ein Großteil der Details ist in diesem Fall jedoch nicht der Fall.

Der Ausdruck ++[[]][+[]]+[+[]] sieht anfangs recht imposant und unübersichtlich aus, ist aber relativ einfach in einzelne Ausdrücke zu unterteilen. Im Folgenden habe ich der Klarheit halber Klammern hinzugefügt. Ich kann Ihnen versichern, dass sie nichts ändern. Wenn Sie dies jedoch überprüfen möchten, können Sie sich über den grouping-Operator informieren. Der Ausdruck kann also klarer als geschrieben werden

( ++[[]][+[]] ) + ( [+[]] )

Um dies aufzuschlüsseln, können wir vereinfachen, indem wir beobachten, dass +[] zu 0 ausgewertet wird. Um sich zu überzeugen, warum dies zutrifft, überprüfen Sie den unary + -Operator und folgen Sie der leicht gewundenen Spur, die schließlich mit ToPrimitive endet, wobei das leere Array in einen leeren String umgewandelt wird, der schließlich in 0 von konvertiert wird ToNumber . Wir können jetzt 0 für jede Instanz von +[] ersetzen:

( ++[[]][0] ) + [0]

Einfacher schon. Was ++[[]][0] betrifft, ist dies eine Kombination aus dem prefix-Inkrementierungsoperator (++), einem array-Literal , das ein Array mit einem einzelnen Element definiert, das selbst ein leeres Array ([[]]) ist, und einem property-Accessor . ([0]) wurde für das vom Arrayliteral definierte Array aufgerufen.

Also können wir [[]][0] einfach auf [] vereinfachen und haben ++[], richtig? Dies ist in der Tat nicht der Fall, da die Auswertung von ++[] einen Fehler auslöst, der anfangs verwirrend erscheinen kann. Ein wenig Überlegung über die Art von ++ macht dies jedoch klar: Es wird verwendet, um eine Variable (z. B. ++i) oder eine Objekteigenschaft (z. B. ++obj.count) zu inkrementieren. Es wird nicht nur zu einem Wert ausgewertet, sondern es wird auch irgendwo gespeichert. Im Fall von ++[] kann der neue Wert nirgendwo abgelegt werden, da es keinen Verweis auf eine zu aktualisierende Objekteigenschaft oder -variable gibt. In Spezifikationen wird dies durch die interne Operation PutValue abgedeckt, die vom Präfix-Inkrement-Operator aufgerufen wird.

Also, was macht ++[[]][0]? Nun, durch eine ähnliche Logik wie +[] wird das innere Array in 0 konvertiert, und dieser Wert wird um 1 erhöht, um einen endgültigen Wert von 1 zu erhalten. Der Wert der Eigenschaft 0 im äußeren Array wird auf 1 aktualisiert, und der gesamte Ausdruck wird in 1 ausgewertet.

Das lässt uns mit

1 + [0]

... das ist eine einfache Verwendung des Additionsoperators . Beide Operanden werden zuerst in Primitive konvertiert. Wenn einer der Primitivwerte ein String ist, wird die String-Verkettung durchgeführt, andernfalls erfolgt die numerische Addition. [0] wird in "0" konvertiert, daher wird die String-Verkettung verwendet, wodurch "10" erzeugt wird.

Als abschließende Bemerkung ist vielleicht nicht sofort ersichtlich, dass das Überschreiben einer der toString()- oder valueOf()-Methoden von Array.prototype das Ergebnis des Ausdrucks ändert, da beide geprüft und verwendet werden, wenn ein Objekt in einen primitiven Wert umgewandelt wird. Zum Beispiel folgendes

Array.prototype.toString = function() {
  return "foo";
};
++[[]][+[]]+[+[]]

... erzeugt "NaNfoo". Warum dies geschieht, bleibt dem Leser als Übung überlassen ...

59
Tim Down

Machen wir es einfach:

++[[]][+[]]+[+[]] = "10"

var a = [[]][+[]];
var b = [+[]];

// so a == [] and b == [0]

++a;

// then a == 1 and b is still that array [0]
// when you sum the var a and an array, it will sum b as a string just like that:

1 + "0" = "10"
22
renatoluna

Dieser wertet gleich aber etwas kleiner aus

+!![]+''+(+[])
  • [] - ist ein konvertiertes Array, das beim Addieren oder Subtrahieren in 0 umgewandelt wird, also + [] = 0
  • ! [] - wird als falsch ausgewertet, also !! [] als wahr
  • + !! [] - konvertiert den Wert "true" in einen numerischen Wert, der den Wert "true" ergibt, in diesem Fall also 1
  • + '' - Fügt dem Ausdruck eine leere Zeichenfolge hinzu, wodurch die Zahl in eine Zeichenfolge umgewandelt wird
  • + [] - wird zu 0 ausgewertet

ist also zu bewerten

+(true) + '' + (0)
1 + '' + 0
"10"

So, jetzt haben Sie das verstanden, versuchen Sie es hier:

_=$=+[],++_+''+$
13
Vlad Shlosberg

+ [] wird zu 0 [...] ausgewertet. Die Summation (+ -Operation) konvertiert den Inhalt des Arrays in eine Zeichenfolgendarstellung, die aus Elementen besteht, die mit Komma verbunden sind.

Alles andere wie das Nehmen des Index des Arrays (haben größere Priorität als + Operation) ist ordinal und ist nichts Interessantes.

7
Eskat0n

Die kürzesten Möglichkeiten, einen Ausdruck in "10" ohne Ziffern auszuwerten, sind:

+!+[] + [+[]] // "10"

-~[] + [+[]] // "10"

// =========== Erläuterung ========== \\

+!+[]: +[] Wandelt in 0 um. !0 konvertiert in true. +true konvertiert in 1 .-~[] = -(-1), was 1 ist

[+[]]: +[] Wandelt in 0 um. [0] ist ein Array mit einem einzelnen Element 0.

Dann wertet JS den 1 + [0] aus, also Number + Array-Ausdruck. Dann funktioniert die ECMA-Spezifikation: Der +-Operator konvertiert beide Operanden in eine Zeichenfolge, indem die toString()/valueOf()-Funktionen vom Basis-Object-Prototyp aufgerufen werden. Sie arbeitet als additive Funktion, wenn beide Operanden eines Ausdrucks nur Zahlen sind. Der Trick ist, dass Arrays ihre Elemente leicht in eine verkettete Zeichenfolgendarstellung konvertieren.

Einige Beispiele:

1 + {} //    "1[object Object]"
1 + [] //    "1"
1 + new Date() //    "1Wed Jun 19 2013 12:13:25 GMT+0400 (Caucasus Standard Time)"

Es gibt eine schöne Ausnahme, dass zwei Objects-Additionen zu NaN führen:

[] + []   //    ""
[1] + [2] //    "12"
{} + {}   //    NaN
{a:1} + {b:2}     //    NaN
[1, {}] + [2, {}] //    "1,[object Object]2,[object Object]"
4
  1. Unary plus gegebener String konvertiert in number 
  2. Inkrementierungsoperator gegebene Zeichenfolge konvertiert und erhöht sich um 1
  3. [] == ''. Leerer String
  4. + '' oder + [] wertet 0 aus.

    ++[[]][+[]]+[+[]] = 10 
    ++[''][0] + [0] : First part is gives zeroth element of the array which is empty string 
    1+0 
    10
    
1
Praveen Vedanth

Schritt für Schritt wird + aus dem Wert in eine Zahl. Wenn Sie ein leeres Array +[]... hinzufügen, da es leer ist und 0 entspricht, wird dies der Fall 

Also von dort, schau jetzt in deinen Code, es ist ++[[]][+[]]+[+[]]...

Und es gibt ein Plus zwischen ihnen ++[[]][+[]] + [+[]]

Diese [+[]] geben also [0] zurück, da sie ein leeres Array haben, das in dem anderen Array in 0 konvertiert wird ...

Der erste Wert ist also ein 2-dimensionales -Array mit einem Array im Inneren ... also ist [[]][+[]] gleich [[]][0], was []... zurückgibt.

Und am Ende ++ konvertieren Sie es und erhöhen Sie es in 1...

Sie können sich also vorstellen, dass 1 + "0""10"...

 Why does return the string “10”?

0
Alireza