En kort introduksjon Til Metaprogrammering i JavaScript
Refleksjon
Refleksjon, unliked «kodegenerering», er en prosess for å endre den underliggende mekanikken i språket. Refleksjon kan skje ved kompileringstid eller ved kjøretid, men vi vil holde fast med runtime reflection som Vi snakker om JavaScript, så kompileringstid refleksjon vil ikke være mulig. Imidlertid kan begreper diskutert her også gjelde for et kompilert språk.Som vi har forstått at refleksjonen handler om å endre den underliggende mekanikken til språket, har den blitt delt inn i tre hovedkategorier, nemlig. introspeksjon, forbønn og modifikasjon.
Introspeksjon
Introspeksjon er prosessen med å analysere programmet. Hvis du kan fortelle hva programmet gjør, kan du endre det som per dine likings. Selv om noen programmeringsspråk ikke støtter kodegenerering eller kodemodifikasjonsfunksjoner, men de tillater sannsynligvis introspeksjon.
et enkelt eksempel på introspeksjon ville være å bruketypeof
ellerinstanceof
operatører I JavaScript. typeof
returnerer gjeldende datatype for en verdi (eller et uttrykk som returnerer en verdi) mensinstanceof
returnerertrue
ellerfalse
hvis lhs-verdien er en forekomst AV RHS-klassen. La oss se dem i aksjon.
i programmet ovenfor har vi brukt typeof
og instanceof
operatører i coerce
– funksjonen for å snuse datatypen for innkommende value
. Dette er den grunnleggende demonstrasjonen av introspeksjon. Et språk som er spesielt utviklet for metaprogrammering, kan imidlertid gi noen kraftige introspeksjonsverktøy.
du kan bruke operatorenin
for å sjekke om det finnes en egenskap i objektet. isNaN
global funksjon kontrollerer om objektet er NaN
. Det er noen statiske metoder bygget rundt Object
for å inspisere verdier av Object
type som Object.isFrozen(value)
for å sjekke om value
er frosset eller Object.keys(value)
for å få egenskapsnavnene til value
– objektet.
TIL ES5 hadde vi disse operatørene og disse metodene å jobbe med. I ES2015 (ES6) introduserte JavaScript Reflect
objekt som gir noen statiske metoder (akkurat som Object
), men spesielt designet for introspeksjon. Siden vi har en egen leksjon på Reflect
, diskuteres disse metodene der.
Forbønn
Forbønn er prosessen med å gripe Inn I JavaScript-prosessene og endre prosessens standardadferd. JavaScript gir gode verktøy for forbønn hvorav den ene er Proxy
.
Proxy
klassen ble introdusert I ES2015 (ES6) for å fange opp (gripe inn) grunnleggende JavaScript-operasjoner rundt objekter akkurat som vi har sett ovenfor, men på en mye bedre måte. Vi har en egen leksjon på
Proxy
(kommer snart), men i et nøtteskall,Proxy
bryter en avskjærbar logikk rundt et objekt.
var targetWithProxy = new Proxy(target, handler);
her er target
objektet og handler
er interceptor. handler
er også et Vanlig JavaScript-objekt, men med noen meningsfulle felt. 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. For eksempel, i programmet ovenfor har vi gitt abstraksjoner over target
objekt og tilpasset hvordan det skal presentere seg for publikum.
noen forbønn var mulig I ES5, så vel som å bruke getter
og setters
på egenskapsbeskrivelser, men det ville resultere i mutasjonen av target
objektet. Proxy
gir en mye renere måte å oppnå forbønn uten å måtte endre det opprinnelige objektet (target
).
Modifikasjon
Modifikasjon refererer til modifikasjonen av programadferd gjennom mutasjon. I tilfelle av forbønn, vi bare snappet opp standard JavaScript prosesser ved å legge en avskjære logikk mellom målet og mottakeren uten å skade målet. I dette tilfellet modifikasjon, endrer vi oppførselen til målet selv så passer mottakeren.
Å Overstyre en funksjonsimplementering ville være et godt eksempel på modifikasjon. For eksempel, hvis en funksjon er utformet for å oppføre seg på en bestemt måte, men vi vil ha noe annet betinget, kan vi gjøre det ved å designe en selvstyrende funksjon. La oss se et eksempel.
i eksemplet ovenfor har vi opprettet en funksjon som overstyrer seg selv med en ny funksjonsimplementering. Dette ville være det hardeste eksempelet på modifikasjon, men vi har andre, kanskje mer meningsfulle brukssaker.
i eksemplet ovenfor har vi brukt Object.defineProperty()
metode for å endre standard egenskapsbeskrivelse for name
egenskapen for å gjøre den skrivebeskyttet. Du kan også brukeObject.freeze()
– metoden for å låse hele objektet for å unngå mutasjoner.
noen forbønner kan skje gjennom modifikasjoner som du kan fra eksemplet ovenfor. Ved å sette writable:false
i egenskapsbeskrivelsen til objektet, derfor muterer objektet (intern implementering), har vi startet verditildelingsoperasjonen.
hvis du ikke er kjent med valueOf
– metoden, brukes den til å tvinge et objekt til en primitiv verdi. Så hvis jeg har et objekt og det har valueOf
metode på seg selv eller på prototypekjeden, kalles Denne metoden Av JavaScript når du prøver å utføre en aritmetisk operasjon på den. Som standard harObject
valueOf
metoden som returnerer seg selv (objektet).
som du kan se i eksemplet ovenfor, emp1/10
resulterte i en NaN
siden et objekt ikke kan deles som naturlige tall. Men senere har vi lagt til valueOf
metode på Employee
klasse som returnerersalary
verdien av objektet. Derforemp2/10
returnerte200
sidenemp2.salary
er200
. På samme måteemp3/10
returnerte300
som vi har lagtvalueOf
metoden direkte påemp3
.
Så i hvert trinn i eksemplet ovenfor griper vi inn i hvordan et objekt presenteres for en standard JavaScript-operasjon og endrer sin oppførsel til våre likings. Dette er ingenting annet enn forbønn.
I ES2015 (ES6) har JavaScript introdusert en ny primitiv datatype som ersymbol
. Det er ingenting som vi har sett før og kan ikke representeres i bokstavelig form. Den kan bare bygges ved å ringeSymbol
– funksjonen.
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)'
i et nøtteskall produserer det unike verdier som også kan brukes som vanlige objekttaster ved hjelp av obj
notasjon der key
ville være et symbol.
var key = Symbol();var obj = {
name: 'Ross',
: 200
};console.log( obj.name ); // 'Ross'
console.log( obj ); // 200
Object.keys(obj); // obj = 300;
siden de er unike, er det ingen måte å lage et duplikat symbol ved et uhell. Hvert nytt symbol er unikt (opprettet med Symbol()
), noe som betyr at hvis du vil bruke et samme symbol, må du lagre det i en variabel og sende den variabelen rundt for å referere til det samme symbolet.
i eksempletvalueOf
kan du se problemet hvis vi ikke er forsiktige eller oppmerksomme. Siden valueOf
er en string
eiendom (som i emp3
kan hvem som helst overstyre det ved et uhell , eller noen som ikke vet om valueOf
kan planlegge å bruke den til eget bruk og tenke «hva ligger det i navnet?».Siden symboler også kan brukes som objektnøkler, Har JavaScript gitt noen globale symboler som skal brukes som objektnøkler for noen Standard JavaScript-operasjoner. Siden disse symbolene er velkjente for en utvikler, kalles de «kjente symboler». Disse kjente symbolene er utsatt for publikum som de statiske egenskapene tilSymbol
funksjon.
Et av de kjente symbolene er Symbol.toPrimitive
som skal brukes som nøkkelen til objektet for å oppnå sin primitive verdi. Ja, du tenker riktig, det er en erstatning for valueOf
metode og det er foretrukket.
💡
toPrimitive
metoden gjør mer enn bare å returnere en tallverdi av objektet. Vennligst les Symbolene leksjoner for å vite mer om det.
JavaScript gir mange slike kjente symboler for å fange opp og endre Standard JavaScript-oppførsel rundt objekter. Vi vil snakke om dette og symboler generelt i Symbolleksjonen.