Articles

o scurtă introducere în Metaprogramarea în JavaScript

reflecție

reflecție, unliked „generarea de cod”, este un proces pentru a schimba mecanica care stau la baza limbii. Reflecția se poate întâmpla în timpul compilării sau în timpul rulării, dar vom rămâne cu reflecția în timpul rulării, deoarece vorbim despre JavaScript, astfel încât reflecția în timpul compilării nu va fi posibilă. Cu toate acestea, conceptele discutate aici ar putea fi aplicabile și unui limbaj compilat.așa cum am înțeles că reflecția se referă la schimbarea mecanicii de bază a limbajului, ea a fost împărțită în trei categorii majore, și anume. introspecție, mijlocire și modificare.

introspecția

introspecția este procesul de analiză a programului. Dacă vă pot spune ce face programul, îl puteți modifica ca pe likings dumneavoastră. Chiar dacă unele limbaje de programare nu acceptă generarea de cod sau caracteristici de modificare a codului, dar cel mai probabil permit introspecția.

un exemplu simplu de introspecție ar fi utilizareatypeofsauinstanceof operatori în JavaScript. typeof returnează tipul de date curent al unei valori (sau o expresie care returnează o valoare) în timp ce instanceof returnează true sau false dacă valoarea LHS este o instanță a clasei RHS. Să le vedem în acțiune.

(introducere / introspecție.js)

în programul de mai sus, am folosit typeof și instanceof operatorii din coerce funcția de a mirosi tipul de date de intrare value. Aceasta este demonstrația de bază a introspecției. Cu toate acestea, un limbaj special conceput pentru metaprogramare ar putea oferi câteva instrumente puternice de introspecție.

puteți utiliza operatorulin pentru a verifica dacă există o proprietate în obiect. isNaN funcția globală verifică dacă obiectul este NaN. Există câteva metode statice construite în jurul Object pentru a inspecta valorile Object tip, cum ar fi Object.isFrozen(value) pentru a verifica dacă value este înghețat sau Object.keys(value) pentru a obține numele proprietății obiectului value.

până la ES5, am avut acești operatori și aceste metode pentru a lucra cu. În ES2015 (ES6), JavaScript a introdus Reflect obiect care oferă unele metode statice (la fel ca Object), dar special concepute pentru introspecție. Deoarece avem o lecție separată despre Reflect, aceste metode sunt discutate acolo.

mijlocirea

mijlocirea este procesul de intervenție în procesele JavaScript și modificarea comportamentului standard al procesului. JavaScript oferă instrumente excelente pentru mijlocire, dintre care unul este Proxy.

Proxy clasa a fost introdusă în ES2015 (ES6) pentru a intercepta (interveni) operațiunile JavaScript de bază în jurul obiectelor la fel cum am văzut mai sus, dar într-un mod mult mai frumos. Avem o lecție separată despre Proxy(în curând), dar pe scurt,Proxy înfășoară o logică interceptabilă în jurul unui obiect.

var targetWithProxy = new Proxy(target, handler);

aici,target este obiect șihandler este interceptorul. handler este, de asemenea, un obiect JavaScript simplu, dar cu unele câmpuri semnificative. For example, handler.get would be a function that returns a custom value when target.prop (here, prop is any property) is accessed.

(introduction/proxy.js)

Proxy is a great way to provide abstractions over your not-so-public data. De exemplu, în programul de mai sus, am furnizat abstracții peste target obiect și personalizat cum ar trebui să se prezinte publicului.

unele mijlociri au fost posibile și în ES5, cum ar fi utilizareagetter șisetters pe descriptorii de proprietate, dar ar duce la mutația obiectuluitargetProxy oferă o modalitate mult mai curată de a realiza mijlocirea fără a fi nevoie să modificați obiectul original (target).

modificare

modificare se referă la modificarea comportamentului programului prin mutație. În cazul mijlocirii, am interceptat doar procesele JavaScript standard adăugând o logică de interceptare între țintă și receptor fără a afecta ținta. În acest caz, modificarea, ne schimbăm comportamentul țintă în sine, astfel se potrivi receptor.

suprascrierea implementării unei funcții ar fi un bun exemplu de modificare. De exemplu, dacă o funcție este proiectată să se comporte într-un anumit fel, dar vrem altceva condiționat, putem face acest lucru proiectând o funcție de sine superioară. Să vedem un exemplu.

(introducere / funcție-modificare.js)

în exemplul de mai sus, am creat o funcție care se înlocuiește cu o nouă implementare a funcției. Acesta ar fi cel mai dur exemplu de modificare, dar avem alte cazuri de utilizare, poate mai semnificative.

(introducere / readonly-obiect.js)

în exemplul de mai sus, am folosit metodaObject.defineProperty() pentru a schimba Descriptorul de proprietate implicit al proprietățiiname pentru a o face doar în citire. De asemenea, puteți utiliza metoda Object.freeze() pentru a bloca întregul obiect pentru a evita orice mutații.

unele mijlociri se pot întâmpla prin modificări, așa cum puteți din exemplul de mai sus. Prin setarea writable:false în descriptorul de proprietate al obiectului, prin urmare mutând obiectul (implementare internă), am început operația de atribuire a valorii.

dacă nu sunteți familiarizați cuvalueOf metoda, este folosit pentru a constrânge un obiect la o valoare primitivă. Deci, dacă am un obiect și are valueOf metodă pe sine sau pe lanțul său prototip, atunci această metodă este apelată de JavaScript atunci când încercați să efectuați o operație aritmetică pe ea. În mod implicit,Object are metodavalueOf care se întoarce (obiectul).

(introducere / valueof.js)

după cum puteți vedea în exemplul de mai sus,emp1/10 a dus la unNaN deoarece un obiect nu poate fi împărțit ca numere naturale. Dar mai târziu am adăugat valueOf metodă pe Employee clasă care returnează salary valoarea obiectului. Prin urmareemp2/10 returnat200 dinemp2.salary este200. În mod similar, emp3/10 a returnat 300 așa cum am adăugat valueOf metoda direct pe emp3.

deci, la fiecare pas din exemplul de mai sus, intervenim modul în care un obiect este prezentat unei operații JavaScript standard și îi schimbăm comportamentul în funcție de preferințele noastre. Aceasta nu este altceva decât mijlocirea.

în ES2015 (ES6), JavaScript a introdus un nou tip de date primitive, care estesymbol. Nu este nimic cum am văzut înainte și nu poate fi reprezentat în formă literală. Poate fi construit doar apelând funcția Symbol.

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)'

pe scurt, produce valori unice care pot fi folosite și ca chei obiect obișnuite folosindobj notație undekey ar fi un simbol.

var key = Symbol();var obj = {
name: 'Ross',
: 200
};console.log( obj.name ); // 'Ross'
console.log( obj ); // 200
Object.keys(obj); // obj = 300;

deoarece sunt unice, nu există nicio modalitate de a crea accidental un simbol duplicat. Fiecare simbol nou este unic (creat folosind Symbol()) ceea ce înseamnă că, dacă doriți să utilizați același simbol, trebuie să îl stocați într-o variabilă și să treceți acea variabilă pentru a se referi la același simbol.

în valueOf exemplu, puteți fața locului problema dacă nu suntem atenți sau conștienți. Deoarece valueOf este o string proprietate (ca în emp3) , oricine o poate suprascrie accidental sau cineva care nu știe despre valueOf ar putea planifica să o folosească pentru propria sa utilizare gândindu-se „ce e pe nume?”.

deoarece simbolurile pot fi folosite și ca chei obiect, JavaScript a furnizat câteva simboluri globale care ar trebui utilizate ca chei obiect pentru unele operații JavaScript standard. Deoarece aceste simboluri sunt bine cunoscute unui dezvoltator, ele sunt numite „simboluri bine cunoscute”. Aceste simboluri cunoscute sunt expuse publicului ca proprietăți statice ale funcțieiSymbol.

unul dintre simbolurile cunoscute esteSymbol.toPrimitive care ar trebui folosit ca cheie a obiectului pentru a obține valoarea sa primitivă. Da, vă gândiți bine, este o înlocuire a metodei valueOf și este preferată.

(introducere / simbol-toprimitiv.js)

XV metodatoPrimitive face mai mult decât returnarea unei valori numerice a obiectului. Vă rugăm să citiți lecțiile de simboluri pentru a afla mai multe despre el.

JavaScript oferă multe astfel de simboluri cunoscute pentru a intercepta și modifica comportamentul JavaScript implicit în jurul obiectelor. Vom vorbi despre acest lucru și despre simboluri în general în lecția simbolurilor.