Vraag Waarom retourneert ++ [[]] [+ []] + [+ []] de string "10"?


Dit is geldig en geeft de string terug "10" in JavaScript (meer voorbeelden hier):

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

Waarom? Wat gebeurt hier?


1439
2017-08-26 08:56


oorsprong


antwoorden:


Als we het opsplitsen, is de rotzooi gelijk aan:

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

In JavaScript is dat waar +[] === 0. + zet iets om in een getal, en in dit geval komt het neer op +"" of 0 (zie specificatiedetails hieronder).

Daarom kunnen we het vereenvoudigen (++ heeft voorrang +):

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

Omdat [[]][0] betekent: haal het eerste element uit [[]], is het waar dat:

  • [[]][0] geeft de innerlijke array terug ([]). Door verwijzingen is het verkeerd om te zeggen [[]][0] === [], maar laten we de innerlijke array noemen A om de verkeerde notatie te vermijden.
  • ++[[]][0] == A + 1, sinds ++ betekent 'met één toenemen'.
  • ++[[]][0] === +(A + 1); met andere woorden, het zal altijd een cijfer zijn (+1 hoeft niet per se een getal terug te geven, terwijl ++ altijd - dankzij Tim Down voor het wijzen van dit uit).

Nogmaals, we kunnen de rommel vereenvoudigen tot iets leesbaarder. Laten we vervangen [] terug voor A:

+([] + 1)
+
[0]

In JavaScript is dit ook waar: [] + 1 === "1", omdat [] == "" (lid worden van een lege array), dus:

  • +([] + 1) === +("" + 1), en
  • +("" + 1) === +("1"), en
  • +("1") === 1

Laten we het nog eenvoudiger maken:

1
+
[0]

Dit geldt ook in JavaScript: [0] == "0", omdat het lid wordt van een array met één element. Bij het samenvoegen worden de elementen gescheiden door ,. Met één element kun je afleiden dat deze logica resulteert in het eerste element zelf.

Dus uiteindelijk krijgen we (nummer + string = string):

1
+
"0"

=== "10" // Yay!

Specificatie details voor +[]:

Dit is een behoorlijk doolhof, maar om te doen +[], eerst wordt het geconverteerd naar een string omdat dat is wat + zegt:

11.4.6 Unary + Operator

De operator unary + converteert de operand naar het type Number.

De productie UnaryExpression: + UnaryExpression wordt als volgt geëvalueerd:

  1. Laat het resultaat zijn van het evalueren van UnaryExpression.

  2. Return ToNumber (GetValue (expr)).

ToNumber() zegt:

Voorwerp

Voer de volgende stappen uit:

  1. Laat primValue ToPrimitive zijn (invoerargument, hint-string).

  2. Return ToString (primValue).

ToPrimitive() zegt:

Voorwerp

Retourneer een standaardwaarde voor het object. De standaardwaarde van een object wordt opgehaald door de interne methode [[DefaultValue]] van het object aan te roepen, waarbij de optionele hint PreferredType wordt doorgegeven. Het gedrag van de [[DefaultValue]] interne methode wordt door deze specificatie gedefinieerd voor alle native ECMAScript-objecten in 8.12.8.

[[DefaultValue]] zegt:

8.12.8 [[DefaultValue]] (hint)

Wanneer de [[DefaultValue]] interne methode van O wordt aangeroepen met hint String, worden de volgende stappen genomen:

  1. Laat toString het resultaat zijn van het aanroepen van de [[Get]] interne methode van object O met argument "toString".

  2. Als IsCallable (toString) waar is,

een. Laat str het resultaat zijn van het aanroepen van de [[Call]] interne methode van toString, met O als de waarde en een lege argumentlijst.

b. Als str een primitieve waarde is, retourneert u str.

De .toString van een array zegt:

15.4.4.2 Array.prototype.toString ()

Wanneer de methode toString wordt aangeroepen, worden de volgende stappen uitgevoerd:

  1. Laat array het resultaat zijn van het aanroepen van ToObject op deze waarde.

  2. Laat func het resultaat zijn van het aanroepen van de [[Get]] interne methode van array met argument "join".

  3. Als IsCallable (func) false is, laat func dan de standaard ingebouwde methode Object.prototype.toString (15.2.4.2) zijn.

  4. Retourneer het resultaat van het aanroepen van de [[Call]] interne methode van func met array als deze waarde en een lege argumentenlijst.

Zo +[] komt neer op +"", omdat [].join() === "".

Nogmaals, de + is gedefinieerd als:

11.4.6 Unary + Operator

De operator unary + converteert de operand naar het type Number.

De productie UnaryExpression: + UnaryExpression wordt als volgt geëvalueerd:

  1. Laat het resultaat zijn van het evalueren van UnaryExpression.

  2. Return ToNumber (GetValue (expr)).

ToNumber is gedefinieerd voor "" als:

De MV van StringNumericLiteral ::: [leeg] is 0.

Zo +"" === 0, en daarom +[] === 0.


1874
2017-08-26 08:58



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

Dan hebben we een string-aaneenschakeling

1+[0].toString() = 10

99
2017-09-14 13:54



Het volgende is overgenomen van a blogpost het beantwoorden van deze vraag die ik heb gepost terwijl deze vraag nog steeds gesloten was. Links zijn naar (een HTML-kopie van) de ECMAScript 3-specificatie, nog steeds de basislijn voor JavaScript in de veelgebruikte webbrowsers van vandaag.

Ten eerste een opmerking: dit soort expressie zal nooit verschijnen in een (gezonde) productieomgeving en is alleen van enig nut als een oefening in hoe goed de lezer de vuile kanten van JavaScript kent. Het algemene principe dat JavaScript-operators impliciet tussen typen converteren, is nuttig, evenals enkele van de gebruikelijke conversies, maar veel van de details in dit geval is dat niet.

De uitdrukking ++[[]][+[]]+[+[]] kan aanvankelijk vrij imposant en obscuur lijken, maar is eigenlijk relatief gemakkelijk op te splitsen in afzonderlijke uitdrukkingen. Hieronder heb ik eenvoudig haakjes toegevoegd voor duidelijkheid; Ik kan je verzekeren dat ze niets veranderen, maar als je dat wilt verifiëren, voel je dan vrij om het te lezen over groepering van operator. Dus, de uitdrukking kan duidelijker worden geschreven als

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

Als we dit onderbreken, kunnen we dit vereenvoudigen door dat waar te nemen +[] evalueert naar 0. Om jezelf ervan te overtuigen waarom dit klopt, kijk eens naar de unary + operator en volg het licht kronkelige pad dat eindigt met ToPrimitive het converteren van de lege array naar een lege string, die vervolgens wordt geconverteerd naar 0 door ToNumber. We kunnen nu vervangen 0 voor elke instantie van +[]:

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

Simpler al. Wat betreft ++[[]][0], dat is een combinatie van de voorvoegsel toename operator (++), an array letterlijk het definiëren van een array met een enkel element dat zelf een lege array is ([[]]) en een eigenschap accessor ([0]) riep de reeks op die door de reeks letterlijk wordt bepaald.

Dus we kunnen vereenvoudigen [[]][0] om gewoon [] en we hebben ++[], toch? In feite is dit niet het geval omdat het evalueren ++[] werpt een fout, die in eerste instantie misschien verwarrend lijkt. Wel een beetje nagedacht over de aard van ++ maakt dit duidelijk: het wordt gebruikt om een ​​variabele (bijv. ++i) of een objecteigenschap (bijv. ++obj.count). Niet alleen evalueert het naar een waarde, het slaat ook die waarde ergens op. In het geval van ++[], het heeft nergens om de nieuwe waarde (wat het ook mag zijn) te plaatsen, omdat er geen verwijzing is naar een objecteigenschap of variabele om bij te werken. In spec-termen is dit gedekt door de interne PutValue bewerking, die wordt aangeroepen door de prefix-incrementoperator.

Wat dan wel ++[[]][0] do? Nou, volgens dezelfde logica als +[], de binnenste array wordt geconverteerd naar 0 en deze waarde wordt verhoogd met 1 om ons een definitieve waarde te geven van 1. De waarde van onroerend goed 0 in de buitenste array is bijgewerkt naar 1 en de hele expressie evalueert naar 1.

Dit laat ons achter

1 + [0]

... wat een eenvoudig gebruik is van de extra operator. Beide operanden zijn de eerste omgezet in primitieven en als een van de primitieve waarden een tekenreeks is, wordt tekenreeksaaneenschakeling uitgevoerd, anders wordt de numerieke optelling uitgevoerd. [0] converteert naar "0", dus wordt string concatenation gebruikt, produceren "10".

Als laatste terzijde, is iets dat misschien niet meteen duidelijk is, dat het een van de toString() of valueOf() methodes van Array.prototype zal het resultaat van de uitdrukking veranderen, omdat beide worden gecontroleerd en gebruikt indien aanwezig bij het omzetten van een object in een primitieve waarde. Bijvoorbeeld het volgende

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

... produceert "NaNfoo". Waarom dit gebeurt blijft achter als een oefening voor de lezer ...


57
2017-12-30 15:41



Laten we het eenvoudig maken:

++[[]][+[]]+[+[]] = "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"

21
2017-12-28 23:13



Deze evalueert naar hetzelfde maar een beetje kleiner

+!![]+''+(+[])
  • [] - is een array geconverteerd die naar 0 is geconverteerd wanneer u er een optelt of ervan aftrekt, dus dus + [] = 0
  • ! [] - evalueert naar false, dus vandaar !! [] evalueert naar true
  • + !! [] - converteert de true in een numerieke waarde die evalueert naar true, dus in dit geval 1
  • + '' - voegt een lege tekenreeks toe aan de expressie waardoor het getal wordt geconverteerd naar een tekenreeks
  • + [] - evalueert naar 0

zo evalueert het ook

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

Dus nu heb je dat, probeer deze:

_=$=+[],++_+''+$

13
2017-08-26 08:58



+ [] evalueert naar 0 [...] vervolgens wordt de array-inhoud opgeteld (+ gebruikt) en wordt de array-inhoud geconverteerd naar de tekenreeksrepresentatie die bestaat uit elementen die zijn samengevoegd met een komma.

Iets anders, zoals het nemen van een array-index (heeft prioriteit voor rasper dan + bewerking) is ordinaal en niets interessants.


7
2017-12-30 08:10



Misschien zijn de kortst mogelijke manieren om een ​​uitdrukking zonder cijfers in "10" te evalueren:

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

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

// ========== Uitleg ========== \\

+!+[] : +[] Converteert naar 0. !0 converteert naar true. +true converteert naar 1. -~[] = -(-1) wat 1 is

[+[]] : +[] Converteert naar 0. [0] is een array met een enkel element 0.

Vervolgens evalueert JS de 1 + [0], dus Number + Array uitdrukking. Dan werkt de ECMA-specificatie: + operator converteert beide operanden naar een tekenreeks door de toString()/valueOf() functies van de basis Object prototype. Het werkt als een additieve functie als beide operanden van een uitdrukking alleen getallen zijn. De truc is dat arrays hun elementen gemakkelijk omzetten in een aaneengeschakelde tekenreeksrepresentatie.

Een paar voorbeelden:

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

Er is een leuke uitzondering dat twee Objects toevoeging resulteert in NaN:

[] + []   //    ""
[1] + [2] //    "12"
{} + {}   //    NaN
{a:1} + {b:2}     //    NaN
[1, {}] + [2, {}] //    "1,[object Object]2,[object Object]"

4



  1. Unary plus gegeven string converteert naar nummer
  2. Toename operator gegeven string converteert en verhoogt met 1
  3. [] == ''. Leeg tekenreeks
  4. + '' of + [] evalueert 0.

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

1