tämä viesti on kunnianosoitus Gary Bernhardtin fantastiselle” Wat ” – puheelle, jossa hän osoittaa joidenkin Ruby-ja JavaScript-kielisten konstruktioiden erikoisuuksia. Jos et ole katsonut puhetta vielä, suosittelen, että otat aikaa ja teet juuri niin! Se on vain noin 4 minuuttia pitkä ja erittäin viihdyttävä, lupaan sen.
puheessaan Gary esittelee nämä neljä katkelmaa JavaScript-koodista:
näemme paljon hakasulkeita, henkseleitä ja plusmerkkejä. Näin nämä fragmentit arvioivat:
+ == ""
+ {} == ""
{} + == 0
{} + {} == NaN
kun näin nämä esimerkit ensimmäistä kertaa, ajattelin: ”Vau, tuo näyttää sotkuiselta!”Tulokset voivat vaikuttaa epäjohdonmukaisilta tai jopa mielivaltaisilta, mutta kestäkää tässä. Kaikki nämä esimerkit ovat itse asiassa hyvin johdonmukaisia eivätkä niin huonoja kuin miltä ne näyttävät!
#Fragment #1: +
aloitetaan ensimmäisestä katkelmasta.:
+ // ""
kuten voimme nähdä, soveltamalla +
operaattori kaksi tyhjää taulukoita johtaa tyhjä merkkijono. Tämä johtuu siitä, että jonon esitysmuoto on kaikkien sen elementtien merkkijonoesitys, joka on yhdistetty pilkun kanssa:
.toString()// "1,2,3".toString()// "1,2".toString()// "1".toString()// ""
tyhjä array ei sisällä mitään elementtejä, joten sen merkkijono esitys on tyhjä merkkijono. Siksi kahden tyhjän merkkijonon yhtymäkohta on vain yksi tyhjä merkkijono.
#Fragment #2: + {}
toistaiseksi kaikki hyvin. Tutkikaamme nyt toista katkelmaa.:
+ {}// ""
huomaa, että koska kyse ei ole kahdesta numerosta, +
– operaattori suorittaa jälleen merkkijonojen yhdistämisen kahden numeerisen arvon lisäämisen sijaan.
edellisessä osassa on jo nähty, että tyhjän joukon merkkijonoesitys on tyhjä merkkijono. Tyhjän kohteen merkkijonoesitys kirjaimellinen tässä on oletusarvo ""
arvo. Tyhjän merkkijonon prepaaminen ei muuta arvoa, joten ""
on lopputulos.
Javascriptissä oliot voivat toteuttaa toString()
– nimisen erikoismenetelmän, joka palauttaa mukautetun merkkijonoesityksen siitä oliosta, johon menetelmää kutsutaan. Tyhjä objektimme ei toteuta tällaista menetelmää, joten olemme palaamassa Object
prototyypin oletustoteutukseen.
#Fragment #3: {} +
väitän, että toistaiseksi tulokset eivät ole olleet yllättäviä. He ovat yksinkertaisesti noudattaneet sääntöjä tyyppi pakkokeinoja ja oletus merkkijono esityksiä JavaScript.
kuitenkin {} +
kehittäjät alkavat hämmentyä:
{} + // 0
miksi näemme 0
(numero nolla), jos kirjoitamme yllä olevan rivin JavaScript-toistoon kuten selainkonsoliin? Eikö tuloksen pitäisi olla naru, kuten + {}
oli?
ennen arvoituksen ratkaisemista tarkastellaan kolmea eri tapaa, joilla +
operaattoria voidaan käyttää:
// 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
kahdessa ensimmäisessä tapauksessa +
operaattori on binäärioperaattori, koska sillä on kaksi operandia (vasemmalla ja oikealla). Kolmannessa tapauksessa +
operaattori on unary-operaattori, koska sillä on vain yksi operandi (oikealla).
tarkastellaan myös {}
kahta mahdollista merkitystä Javascriptissä. Yleensä kirjoitamme {}
tarkoittamaan tyhjää objektia kirjaimella, mutta jos olemme statement-asemassa, JavaScriptin kielioppi määrittää {}
tarkoittamaan tyhjää lohkoa. Seuraava koodinpätkä määrittelee kaksi tyhjää palikkaa, joista yksikään ei ole objekti kirjaimellinen:
{}// Empty block{ // Empty block}
Katsotaanpa palastamme uudelleen.:
{} +
anna minun muuttaa välilyöntiä hieman, jotta se selkeyttää, miten JavaScript-moottori näkee koodin:
{ // Empty block}+;
nyt näemme selvästi, mitä täällä tapahtuu. Meillä on lohkolauseke, jota seuraa toinen lauseke, joka sisältää tyhjällä matriisilla toimivan unary +
– lausekkeen. Puolipiste lisätään automaattisesti ASI: n sääntöjen mukaisesti (automaattinen puolipiste).
voit helposti tarkistaa selainkonsolistasi, että +
arvioi arvoksi 0
. Tyhjässä jonossa on sen merkkijonoesityksenä tyhjä merkkijono, jonka +
operaattori puolestaan muuntaa luvuksi nolla. Lopuksi selainkonsoli ilmoittaa viimeisen lausekkeen arvon (+
, tässä tapauksessa).
Vaihtoehtoisesti voit syöttää molemmat koodinpätkät JavaScript-jäsentimeen, kuten Esprimaan, ja vertailla syntyneitä abstrakteja syntaksipuita. Tässä on AST varten + {}
:
{ "type": "Program", "body": }, "right": { "type": "ObjectExpression", "properties": } } } ], "sourceType": "script"}
ja tässä on AST {} +
:
{ "type": "Program", "body": }, { "type": "ExpressionStatement", "expression": { "type": "UnaryExpression", "operator": "+", "argument": { "type": "ArrayExpression", "elements": }, "prefix": true } } ], "sourceType": "script"}
sekaannus juontaa juurensa JavaScript-kieliopin vivahteesta, jossa käytetään henkseleitä sekä objektiluvuille että palikoille. Lauseasennossa avaussuoja aloittaa lohkon, kun taas lauseasennossa avaussuoja aloittaa objektin kirjaimellisen.
#Fragment #4: {} + {}
lopuksi, katsotaanpa nopeasti katsomaan viimeinen pala {} + {}
:
{} + {}// NaN
no, lisäämällä kaksi objekti literals on kirjaimellisesti ”ei numero” — mutta lisäämme kaksi objekti literals tässä? Älä anna hammasrautojen hämätä enää! Tästä on kyse.:
{ // Empty block}+{};
se on aika lailla sama juttu kuin edellisessä esimerkissä. Sovellamme nyt unary plus-operaattoria tyhjään kohteeseen kirjaimellisesti. Se on periaatteessa sama kuin tekisi Number({})
, jolloin tuloksena on NaN
, koska kappalettamme kirjaimellinen ei voi muuntaa luvuksi.
jos haluat JavaScript-moottorin jäsentävän koodin kahtena tyhjänä objektilitrana, kääri ensimmäinen (tai koko koodinpala) sulkeisiin. Sinun pitäisi nyt nähdä odotettu tulos:
({}) + {}// ""({} + {})// ""
avaussulkeet saavat jäsentäjän yrittämään tunnistaa lausekkeen, minkä vuoksi se ei käsittele {}
lohkoa (joka olisi lauseke).
# Yhteenveto
nyt pitäisi nähdä, miksi neljä koodinpätkää arvioivat, miten ne tekevät. Se ei ole mielivaltaista tai sattumanvaraista lainkaan, vaan tyyppipakotteen sääntöjä sovelletaan täsmälleen määrittelyn ja kielen kieliopin mukaisesti.
pidä mielessä, että jos avaustuki on ensimmäinen lauseessa esiintyvä merkki, se tulkitaan lohkon alkuna eikä objektin kirjaimena.