Analysere JavaScript-Eksemplene I Gary Bernhardts «Wat» Talk

Dette innlegget er en hyllest Til Gary Bernhardts fantastiske «Wat» – snakk der han peker på særegenheter ved noen språkkonstruksjoner I Ruby og JavaScript. Hvis du ikke har sett samtalen ennå, anbefaler jeg sterkt at du tar deg tid og gjør nettopp det! Det er bare ca 4 minutter lang og svært underholdende, jeg lover.

I sin tale viser Gary disse fire fragmentene Av JavaScript-kode:

 Særegenheter I JavaScript

vi ser mange braketter, braces og plusstegn. Her er hva disse fragmentene vurderer å:

  • + == ""
  • + {} == ""
  • {} + == 0
  • {} + {} == NaN

Da jeg så disse eksemplene for første gang, tenkte jeg: «Wow, det ser rotete ut!»Resultatene kan virke inkonsekvent eller vilkårlig, men bære med meg her. Alle disse eksemplene er faktisk veldig konsekvent og ikke så ille som de ser ut!

#Fragment #1: +

la oss starte med det første fragmentet:

 + // ""

Som vi kan se, resulterer bruk av + – operatøren til to tomme arrays i en tom streng. Dette skyldes at strengrepresentasjonen av en matrise er strengrepresentasjonen av alle dens elementer, sammenkoblet sammen med kommaer:

.toString()// "1,2,3".toString()// "1,2".toString()// "1".toString()// ""

en tom matrise inneholder ingen elementer, så strengrepresentasjonen er en tom streng. Derfor er sammenkoblingen av to tomme strenger bare en annen tom streng.

#Fragment #2: + {}

Så langt, så bra. La oss nå undersøke det andre fragmentet:

 + {}// ""

Merk at fordi vi ikke arbeider med to tall, utfører operatoren + igjen streng sammenkobling i stedet for tillegg av to numeriske verdier.

i den forrige delen har vi allerede sett at strengrepresentasjonen av et tomt array er en tom streng. Strengrepresentasjonen av den tomme objekt bokstavelig her er standardverdien "". Prepending en tom streng endrer ikke verdien, så "" er det endelige resultatet.

i JavaScript kan objekter implementere en spesiell metode kalt toString() som returnerer en tilpasset strengrepresentasjon av objektet metoden kalles på. Vår empty object literal implementerer ikke en slik metode, så vi faller tilbake til standardimplementeringen av prototypen Object.

#Fragment #3: {} +

jeg vil hevde at så langt har resultatene ikke vært for uventede. De har ganske enkelt fulgt reglene for type tvang og standard strengrepresentasjoner I JavaScript.

men {} + er hvor utviklere begynner å bli forvirret:

{} + // 0

Hvorfor ser vi 0 (tallet null) hvis vi skriver inn linjen ovenfor i En JavaScript-REPL som nettleserkonsollen? Skal ikke resultatet være en streng, akkurat som + {} var?

før vi løser gåten, bør du vurdere de tre forskjellige måtene + operatøren kan brukes på:

// 1) Addition of two numeric values2 + 2 == 4// 2) String concatenation of two values"2" + "2" == "22"// 3) Conversion of a value to a number+2 == 2+"2" == 2

i de to første tilfellene er + – operatøren en binær operatør fordi den har to operander (til venstre og til høyre). I det tredje tilfellet er + – operatøren en unær operatør fordi den bare har en enkelt operand (til høyre).

vurder også de to mulige betydningene av {} I JavaScript. Vanligvis skriver vi {} for å bety en tom objekt bokstavelig, men hvis Vi er i setningsposisjon, Angir JavaScript-grammatikken {} for å bety en tom blokk. Følgende stykke kode definerer to tomme blokker, hvorav ingen er et objekt bokstavelig:

{}// Empty block{ // Empty block}

La oss ta en titt på vårt fragment igjen:

{} + 

La meg endre mellomrom litt for å gjøre det tydeligere hvordan JavaScript-motoren ser koden:

{ // Empty block}+;

Nå kan vi tydelig se hva som skjer her. Vi har en blokk setning etterfulgt av en annen setning som inneholder en unary + uttrykk som opererer på en tom matrise. Etterfølgende semikolon settes inn automatisk i HENHOLD TIL asi-reglene (automatisk semikoloninnsetting).

du kan enkelt kontrollere i nettleserkonsollen at + evalueres til 0. Den tomme matrisen har en tom streng som strengrepresentasjon, som igjen konverteres til tallet null av operatøren +. Endelig rapporteres verdien av den siste setningen (+, i dette tilfellet) av nettleserkonsollen.

Alternativt kan du mate begge kodebitene til En JavaScript-parser som Esprima og sammenligne de resulterende abstrakte syntaxtrærne. Her er AST for + {}:

{ "type": "Program", "body": }, "right": { "type": "ObjectExpression", "properties": } } } ], "sourceType": "script"}

Og her er AST for {} + :

{ "type": "Program", "body": }, { "type": "ExpressionStatement", "expression": { "type": "UnaryExpression", "operator": "+", "argument": { "type": "ArrayExpression", "elements": }, "prefix": true } } ], "sourceType": "script"}

forvirringen stammer fra en nyanse Av JavaScript-grammatikken som bruker braces både for objektlitteraler og blokker. I setningsposisjon starter en åpningsbøyle en blokk, mens i uttrykksposisjon starter en åpningsbøyle en objekt bokstavelig.

#Fragment #4: {} + {}

Til Slutt, la oss raskt ta en titt på vårt siste fragment {} + {}:

{} + {}// NaN

vel, å legge til to objektlitteraler er bokstavelig talt » ikke et tall — – men legger vi til to objektlitteraler her? Ikke la bukseseler lure deg igjen! Dette er hva som skjer:

{ // Empty block}+{};

det er ganske mye den samme avtalen som i forrige eksempel. Imidlertid bruker vi nå unary plus-operatoren til et tomt objekt bokstavelig. Det er i utgangspunktet det samme som å gjøre Number({}), noe som resulterer i NaN fordi vårt objekt bokstavelig ikke kan konverteres til et tall.

hvis Du vil At JavaScript-motoren skal analysere koden som to tomme objektlitteraler, pakk den første (eller hele koden) i parentes. Du bør nå se det forventede resultatet:

({}) + {}// ""({} + {})// ""

åpningsparentesen får parseren til å forsøke å gjenkjenne et uttrykk, og derfor behandler den ikke {} som en blokk (som ville være en setning).

#Sammendrag

du bør nå se hvorfor de fire kodefragmentene vurderer måten de gjør. Det er ikke vilkårlig eller tilfeldig i det hele tatt; reglene for type tvang brukes akkurat som fastsatt i spesifikasjonen og språkgrammatikken.

bare husk at hvis en åpningsbøyle er det første tegnet som vises i en setning, tolkes det som starten på en blokk i stedet for en objekt bokstavelig.

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert.