(! [] + []) [+ []]… Erklären Sie, warum dies funktioniert

106
alert((![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]);

Die Ausgabe dieses Codes lautet : fail. Warum?

Übrigens (![]+[])[+!+[]] == 'false'[1], richtig? Aber warum ![]+[] == "false"und warum +!+[] == 1?

cdxf
quelle
14
@ Noob Ich vertraue dir nicht. Am Ende ist es eine Gabelbombe.
Johannes Schaub - Litb
3
Es ist natürlich ein String-Literal;)
Yi Jiang
3
(![]+[])[+[]]ist "f" (das erste Zeichen von "false"), (![]+[])[+!+[]]ist "a" usw.
Mauricio Scheffer
3
@ Noob: Wie Sie sagten, können Sie jeden Ausdruck in Ihrem Browser testen. Versuchen Sie es alert(![]+[])dann alert(+!+[])und Sie werden sehen.
Mauricio Scheffer
12
Nutzlos oder nicht, ich finde es eine interessante Frage und würde gerne eine gut formulierte Erklärung sehen. Viele Code Golfs würden geschlossen, wenn Nützlichkeit oder Praktikabilität berücksichtigt würden. Übungen und Spiele sind an und für sich nützlich, um den Geist und den Denkprozess zu erweitern.
John K

Antworten:

127

Wie @Mauricio kommentierte, (![]+[])[+[]]ist "f" (das erste Zeichen von "false"),(![]+[])[+!+[]]) ist "a", etc ...

Wie funktioniert es?

Untersuchen wir das erste Zeichen 'f':

(![]+[])[+[]]; // 'f'

Der erste Teil des Ausdrucks - in Klammern - besteht aus ![]+[]dem ersten Operanden des Addition-Operators ![]und wird erzeugt false, da ein Array-Objekt - wie jede andere Objektinstanz - wahr ist und das logische (!) NICHT unär anwendet Operator, es erzeugt falsezum Beispiel den Wert .

![]; // false, it was truthy
!{}; // false, it was truthy
!0;  // true, it was falsey
!NaN;  // true, it was falsey

Danach haben wir den zweiten Operanden der Addition, ein leeres Array. []Dies dient nur zum Konvertieren des falseWerts in einen String, da die String-Darstellung eines leeren Arrays nur ein leerer String ist.

false+[]; // "false"
false+''; // "false"

Der letzte Teil, das Paar eckiger Klammern nach den Klammern, ist der Eigenschaftszugriff und sie erhalten einen Ausdruck, der vom Unary Plus-Operator gebildet wird, der erneut auf ein leeres Array angewendet wird.

Der Unary Plus-Operator führt eine Typkonvertierung durch Number, zum Beispiel in:

typeof +"20"; // "number"

Ein weiteres Mal wird dies auf ein leeres Array angewendet. Wie bereits erwähnt, ist die Zeichenfolgendarstellung eines Arrays eine leere Zeichenfolge. Wenn Sie eine leere Zeichenfolge in Zahl konvertieren, wird sie in Null konvertiert:

+[]; // 0, because
+[].toString(); // 0, because
+""; // 0

Daher können wir den Ausdruck in einigen Schritten "dekodieren":

(![]+[])[+[]];
(false+[])[+[]];
(false+'')[+[]];
(false+'')[0];
('false')[0];  // "f"

Beachten Sie, dass der Zugriff auf Zeichen mithilfe der Klammernotation für Zeichenfolgenwerte nicht Teil von ECMAScript 3 war. Editionsspezifikation, (deshalb diecharAt Methode).

Diese Art von "Indexeigenschaften", die die Zeichen einer Zeichenfolge darstellen, wurden jedoch in ECMAScript 5 standardisiert, und bereits vor der Standardisierung war die Funktion in einer Reihe von Browsern verfügbar (sogar in IE8 (Standardmodus)).

CMS
quelle
46
Hoffe nur, dass dies nie eine Interviewfrage ist.
Inisheer
4
@JTA: Ich hoffe es ist ! Ich hätte bestanden :-D
Mauricio Scheffer
18
Woher kommt das "i"?
Josh Stodola
5
@rlemon, es gibt keinen intDatentyp in der Sprache. Tatsächlich haben alle Zahlen ein 64-Bit-Format mit doppelter Genauigkeit (IEEE 754-Werte), obwohl einige Operatoren intern mit ganzzahligen Werten arbeiten (wie die bitweisen Operatoren), ist das Ergebnis immer ein Doppel . Das 'i'kommt in diesem Beispiel von undefined, aber es könnte Infinityzum Beispiel kommen von : (+!+[]/+[+[]]+[])[!+[]+!+[]+!+[]]=> (1/0+'')[3]=> (Infinity+'')[3]=>'i'
CMS
5
@ JoshStodola Nun, ~ 3 Monate später eine weitere Klarstellung. Das "i" kommt in diesem Fall von "undefined", ja, aber hier geht es um einen anderen Trick. Der Code verkettet "false" mit "undefined", um eine "falseundefined"(mit :) konstruierte Form zu bilden, [![]]+[][[]]in der der Index von "i" 10 +!+[]+[+[]]ergibt "10". Dies wird verwendet, um das "i" zu extrahieren (String-Indizes können in Javascript verwendet werden, wenn sie anscheinend zu ganzen Zahlen gezwungen werden können). Das letzte Konstrukt, das es erzeugt, ist:([![]]+[][[]])[+!+[]+[+[]]]
Entropie