Lyhyt johdatus Metaprogramming in JavaScript
Reflection
Reflection, unliked ”code generation”, on prosessi, jolla muutetaan kielen taustalla olevaa mekaniikkaa. Reflection voi tapahtua compile-time tai runtime, mutta pidämme kiinni runtime reflection koska puhumme JavaScript, joten compile-time reflection ei ole mahdollista. Tässä käsitellyt käsitteet voisivat kuitenkin soveltua myös käännettyyn kieleen.
koska olemme ymmärtäneet, että pohdinnassa on kyse kielen taustalla olevan mekaniikan muuttamisesta, se on jaettu kolmeen pääluokkaan, viz. itsetutkiskelu, esirukous ja muokkaus.
Introspektio
Introspektio on prosessi, jossa ohjelmaa analysoidaan. Jos voit kertoa, mitä ohjelma tekee, voit muokata sitä kohti likeings. Vaikka jotkut ohjelmointikielet eivät tue koodin luomista tai koodin muokkaamista, mutta ne todennäköisesti mahdollistavat itsetutkiskelun.
yksinkertainen esimerkki introspektiosta olisi typeof
tai instanceof
operaattorit Javascriptissä. typeof
palauttaa nykyisen tietotyypin arvon (tai arvon palauttavan lausekkeen), kun taas instanceof
palauttaa true
tai false
jos LHS-arvo on RHS-luokan ilmentymä. Katsotaan, miten he toimivat.
edellä mainitussa ohjelmassa on käytetty typeof
ja instanceof
operaattorit coerce
funktio haistaa saapuvan value
. Tämä on itsetutkiskelun perusesitys. Erityisesti metaohjelmointiin suunniteltu kieli saattaa kuitenkin tarjota tehokkaita itsetutkiskeluvälineitä.
voit käyttää isNaN
global function checks if object is NaN
Object
Object
tyypin Object.isFrozen(value)
tarkistaa, onko value
jäätynyt tai Object.keys(value)
saada kiinteistöjen nimet value
objekti.
ES5: een asti meillä oli näitä operaattoreita ja näiden menetelmien kanssa toimimista. Es2015: ssä (ES6) JavaScript esitteli Reflect
objektin, joka tarjoaa joitakin staattisia menetelmiä (aivan kuten Object
), mutta erityisesti itsetutkiskeluun suunniteltuja. Koska meillä on erillinen Oppitunti Reflect
, näitä menetelmiä käsitellään siellä.
esirukous
esirukous on prosessi, jossa JavaScript-prosesseihin puututaan ja prosessin vakiokäyttäytymistä muutetaan. JavaScript tarjoaa loistavia työkaluja esirukoukseen, joista yksi on Proxy
.
Proxy
Luokka otettiin käyttöön ES2015 (ES6): ssä pysäyttämään (intervent) perus JavaScript-toiminnot objektien ympärillä aivan kuten edellä on nähty, mutta paljon mukavammalla tavalla. Meillä on erillinen Oppitunti Proxy
(tulossa pian), mutta pähkinänkuoressa Proxy
kietoo kuuntelevan logiikan objektin ympärille.
var targetWithProxy = new Proxy(target, handler);
täällä target
on kohde ja handler
on torjuntahävittäjä. handler
on myös pelkkä JavaScript-objekti, mutta siinä on joitakin merkityksellisiä kenttiä. For example, handler.get
would be a function that returns a custom value when target.prop
(here, prop
is any property) is accessed.
Proxy is a great way to provide abstractions over your not-so-public data. Esimerkiksi yllä olevassa ohjelmassa olemme tarjonneet abstraktioita target
object ja räätälöineet, miten sen tulisi esiintyä yleisölle.
ES5: ssä oli myös mahdollista käyttää getter
ja setters
ominaisuuskuvauksissa, mutta se johtaisi target
objektin mutaatioon. Proxy
tarjoaa huomattavasti puhtaamman tavan saavuttaa esirukous ilman, että alkuperäistä kohdetta tarvitsee muokata (target
).
modifikaatiolla
modifikaatiolla tarkoitetaan ohjelman käyttäytymisen muuttamista mutaation kautta. Kun kyseessä on intercess, me vain siepata standardin JavaScript prosesseja lisäämällä kuuntelulogiikka kohteen ja vastaanottimen vahingoittamatta kohde. Tässä tapauksessa muutos, olemme muuttamassa käyttäytymistä kohde itse niin sopivat vastaanotin.
funktion toteutuksen ohittaminen olisi hyvä esimerkki muutoksesta. Esimerkiksi jos funktio on suunniteltu käyttäytymään tietyllä tavalla, mutta haluamme jotain muuta ehdollisesti, voimme tehdä sen suunnittelemalla itsesäätävän funktion. Katsotaanpa esimerkkiä.
yllä olevassa esimerkissä on luotu funktio, joka ohittaa itsensä uudella funktion toteutuksella. Tämä olisi karuin esimerkki modifioinnista, mutta meillä on muitakin, ehkä mielekkäämpiä käyttötapauksia.
yllä olevassa esimerkissä olemme käyttäneet Object.defineProperty()
menetelmää name
ominaisuuden oletuskuvauksen muuttamiseksi siten, että se on vain luku-ominaisuus. Voit myös käyttää Object.freeze()
– menetelmää lukita koko objekti mutaatioiden välttämiseksi.
jotkut esirukoukset voivat tapahtua muokkausten avulla, kuten yllä olevasta esimerkistä voi päätellä. Asettamalla writable:false
objektin ominaisuuskuvaukseen, eli muuntamalla objektia (sisäinen toteutus), olemme inceptoineet arvon määritysoperaation.
Jos et tunne valueOf
– menetelmää, sitä käytetään taivuttamaan objekti alkeisarvoon. Eli jos minulla on objekti ja sillä on valueOf
menetelmä itsessään tai sen prototyyppiketjussa, niin tätä menetelmää kutsutaan Javascriptillä, kun sille yritetään suorittaa aritmeettinen operaatio. Oletuksena Object
on valueOf
menetelmä, joka palauttaa itsensä (olio).
kuten yllä olevasta esimerkistä näkyy, emp1/10
johti NaN
koska kohdetta ei voi jakaa kuin luonnollisia lukuja. Mutta myöhemmin on lisätty valueOf
method on Employee
class that returns salary
value of the object. Siksi emp2/10
palasi 200
koska emp2.salary
on 200
. Samoin emp3/10
palasi 300
, koska olemme lisänneet valueOf
metodin suoraan emp3
.
joten jokaisessa vaiheessa edellä esimerkissä puutumme siihen, miten objekti esitetään tavalliselle JavaScript-toiminnolle, ja muutamme sen käyttäytymistä meidän tykkäyksiimme. Tämä on pelkkä esirukous.
Es2015: ssä (ES6) JavaScript on ottanut käyttöön uuden alkeellisen tietotyypin, joka on symbol
. Se ei ole mitään, mitä olemme nähneet aiemmin, eikä sitä voida esittää kirjaimellisessa muodossa. Se voidaan konstruoida vain kutsumalla Symbol
funktioksi.
var sym1 = Symbol();
var sym2 = Symbol();
var sym3 = Symbol('description'); // description for debugging aidsym1 === sym2 // false
sym1 === sym2 // falsetypeof sym1 // 'symbol'console.log( sym1 ); // 'Symbol()'
console.log( sym3 ); // 'Symbol(description)'
pähkinänkuoressa se tuottaa uniikkeja arvoja, joita voidaan käyttää myös tavallisina objektinavaimina käyttämällä obj
notaatiota, jossa key
olisi symboli.
var key = Symbol();var obj = {
name: 'Ross',
: 200
};console.log( obj.name ); // 'Ross'
console.log( obj ); // 200
Object.keys(obj); // obj = 300;
koska ne ovat uniikkeja, ei ole mahdollista luoda päällekkäistä symbolia vahingossa. Jokainen uusi symboli on uniikki (luotu käyttämällä Symbol()
), mikä tarkoittaa, että jos haluat käyttää samaa symbolia, sinun täytyy tallentaa se muuttujaan ja siirtää tämä muuttuja ympäri viitataksesi samaan symboliin.
valueOf
esimerkissä ongelman voi havaita, jos emme ole varovaisia tai tietoisia. Koska valueOf
on string
ominaisuus (kuten emp3
) , kuka tahansa voi ohittaa sen vahingossa tai joku, joka ei tiedä valueOf
voisi suunnitella käyttävänsä sitä omaan käyttöönsä ajatellen ”mitä onko nimi?”.
koska symboleita voidaan käyttää myös objektiavaimina, JavaScript on tarjonnut joitakin yleisiä symboleita, joita tulisi käyttää objektiavaimina joissakin tavallisissa JavaScript-toiminnoissa. Koska nämä symbolit ovat hyvin tunnettuja kehittäjälle, niitä kutsutaan ”tunnetuiksi symboleiksi”. Nämä tunnetut symbolit paljastuvat yleisölle Symbol
funktion staattisina ominaisuuksina.
yksi tunnetuista symboleista on Symbol.toPrimitive
, jota tulisi käyttää olion avaimena sen alkeellisen arvon saamiseksi. Kyllä, ajattelet oikein, se on korvaava valueOf
metodi ja sitä suositaan.
💡
toPrimitive
menetelmä tekee muutakin kuin palauttaa kohteen lukuarvon. Lue symbolit oppitunteja tietää enemmän siitä.
JavaScript tarjoaa monia tällaisia tunnettuja symboleita, joilla voidaan siepata ja muokata JavaScript-oletuskäyttäytymistä objektien ympärillä. Puhumme tästä ja symboleista yleensä symbolien oppitunnilla.