Cum sunt create obiectele în js. Programare orientată pe obiecte. Folosind funcția constructor

Obiecte JavaScript

În precedent Lecții de JavaScript Ați văzut că există mai multe obiecte încorporate, cum ar fi String, Date, Array și altele. Pe lângă aceste obiecte încorporate, vă puteți crea și propriile obiecte.

Obiectul este tip special date cu un set de proprietăți și metode.

Să ilustrăm acest lucru cu un exemplu: Persoana este un obiect. Proprietățile sunt valori asociate unui obiect. Proprietățile persoanei includ numele, înălțimea, greutatea, vârsta, culoarea pielii, culoarea ochilor etc. Toate persoanele au aceste proprietăți, dar valorile acestor proprietăți vor diferi de la o persoană la alta. Obiectele au și metode. Metodele sunt acțiuni care pot fi efectuate asupra obiectelor. Metodele de persoană pot include eat(), sleep(), work(), play(), etc.

Proprietăți

Sintaxa pentru accesarea proprietății unui obiect este:

Codul de mai sus va genera următoarea ieșire:

Cometariu: Parametrii trecuți metodei sunt încadrați în acolade.

Un exemplu de apelare a metodei sleep() a obiectului personObj:

sintaxă alternativă (folosind literale obiect):

2. Creați un constructor de obiecte

Creăm o funcție care inițializează obiecte:

persoană cu funcție (prenume, prenume, vârstă, culoarea ochilor)
{
this.firstname=prenume;
this.lastname=nume;
this.age=varsta;
this.eyeculo=culoarea ochilor;
}

În interiorul funcției, trebuie să atribuiți valori proprietăților folosind constructul this.PropertyName. Motivul pentru această sintaxă este că veți folosi mai mult de o instanță a unui obiect (persoană) la un moment dat (și trebuie să fie clar cu ce obiect specific aveți de-a face). Prin urmare, cuvântul „acest” indică un obiect specific - curent ale cărui proprietăți le inițializați în constructor.

Odată ce ați scris constructorul unui obiect, puteți crea instanțe noi ale obiectului, astfel:

Rețineți că metodele sunt doar funcții obișnuite atașate obiectelor. În continuare trebuie să scriem corpul funcției newlastname().

Obiectele sunt piatra de temelie a JavaScript. Multe tipuri de date încorporate sunt reprezentate ca obiecte. Pentru a fi un dezvoltator JavaScript de succes, trebuie să înțelegeți clar modul în care funcționează. Blocurile de construcție ale unui obiect se numesc câmpurile sale sau proprietățile obiectului JavaScript. Sunt folosite pentru a descrie orice aspect al unui obiect. Proprietatea ar putea descrie lungimea unei liste, culoarea cerului sau data nașterii unei persoane. Crearea obiectelor este un proces ușor. Limbajul oferă o sintaxă cunoscută sub numele de literale obiect, care sunt notate cu acolade.

Accesarea Proprietăților

Limba oferă două intrări pentru accesarea proprietăților. Prima și cea mai comună este cunoscută sub numele de notație punct. În notație cu puncte, o resursă poate fi accesată specificând numele obiectului gazdă, urmat de punct și numele proprietății. De exemplu, când object.foo a fost setat inițial la unu, atunci valoarea sa va deveni 2 după ce instrucțiunea JavaScript objects este executată.

O sintaxă alternativă de acces este cunoscută sub numele de notație paranteze. În notație, numele obiectului este urmat de un set de paranteze drepte. În ele, numele proprietății este specificat ca șir:

obiect["foo"] = obiect["foo"] + 1.

Este mai expresiv decât notația cu puncte, deoarece permite unei variabile să specifice întregul sau parțial numele unei proprietăți. Acest lucru este posibil deoarece interpretul de obiect JavaScript convertește automat această expresie într-un șir și apoi obține proprietatea corespunzătoare. Numele proprietăților sunt create din mers prin concatenarea conținutului variabilei f cu șirul „oo”:

obiect = „bară”.

Notarea cu paranteze permite numelor de proprietăți să conțină caractere care sunt interzise în notația cu puncte. De exemplu, următoarea afirmație este complet legală între paranteze. Cu toate acestea, dacă utilizatorul încearcă să creeze același nume de proprietate în notație cu puncte, va întâlni o eroare de sintaxă:

obiect["!@#$% &*()."] = adevărat.

Proprietățile obiectelor JavaScript imbricate pot fi accesate prin înlănțuirea de puncte și/sau paranteze. De exemplu, următorul obiect conține un obiect imbricat numit baz care conține un alt obiect numit foo care are o proprietate numită bar care conține valoarea cinci:

var obiect = ( baz: ( foo: ( bar: 5 ) ) ).

Următoarele expresii accesează proprietatea atașată barei. Prima expresie folosește notația punct, în timp ce a doua expresie folosește notația pătrată. A treia expresie combină ambele intrări pentru a obține același rezultat:

  • obiect.baz.foo.bar;
  • obiect["baz"]["foo"]["bar"];
  • obiect["baz"].foo["bar"].

Expresii precum cele prezentate în exemplul anterior pot cauza degradarea performanței dacă sunt utilizate incorect și pot duce la eșecul obiectului JavaScript. Evaluarea fiecărei expresii punct sau paranteză necesită timp. Dacă aceeași proprietate este folosită de mai multe ori, atunci este logic să accesați proprietatea o dată și apoi să stocați valoarea într-o variabilă locală pentru toate utilizările viitoare.

Funcționează ca metodă

Când o funcție este folosită ca proprietate a unui obiect, se numește metodă. La fel ca și proprietățile, ele sunt specificate în notația literală a obiectului. De exemplu:

var obiect = ( suma: function(foo, bar) ( return foo + bar; ) ).

Metodele obiectelor JavaScript pot fi apelate folosind semne și paranteze. Următorul exemplu apelează metoda sum() din exemplul anterior folosind ambele intrări:

  • obiect.sumă(1, 2);
  • obiect[„sumă”](1, 2).

Notația literală a obiectelor este utilă pentru crearea de noi obiecte, dar nu poate adăuga proprietăți sau metode celor existente. Din fericire, adăugarea de date noi este la fel de ușoară ca și crearea unei declarații de atribuire. Este creat un obiect gol. Apoi, folosind operatori de atribuire, adăugăm două proprietăți, foo și bar, și metoda baz:

  • var obiect = ();
  • obiect.foo = 1;
  • obiect.bar = nul;
  • object.baz = function() ( returnează „bună ziua de la baz()”; ).

Încapsularea programului

Ideea de bază a programării orientate pe obiect este de a împărți programele în părți mai mici și de a face fiecare parte responsabilă pentru gestionarea propriei stări. Astfel, unele cunoștințe despre cum funcționează o parte a unui program pot fi locale acelei părți. Cineva care lucrează la restul programului nu ar trebui să-și amintească sau chiar să știe despre el. Ori de câte ori aceste date locale se modifică, trebuie actualizat doar codul imediat din jurul lor.

Diferitele părți ale unui astfel de program interacționează între ele prin interfețe, seturi limitate funcții sau legături care oferă funcționalitate utilă la un nivel mai abstract în timp ce ascund implementarea lor exactă. Astfel de părți ale unui program sunt modelate folosind obiecte. Interfața lor constă din un anumit set metode si proprietati. Proprietățile care fac parte dintr-o interfață sunt numite publice. Restul, care nu ar trebui să atingă codul extern, se numesc private.

Multe limbi oferă posibilitatea de a distinge între proprietățile publice și private și nu permit codului extern să acceseze cele private. JavaScript, care adoptă din nou o abordare minimalistă, nu există încă. În prezent se lucrează pentru adăugarea acestei limbi. Prin urmare, programatorii JavaScript vor folosi cu succes această idee. De obicei, interfața disponibilă este descrisă în documentație sau comentarii. De asemenea, este o practică obișnuită să plasați o liniuță de subliniere (_) la începutul numelor de proprietate pentru a indica faptul că acele proprietăți sunt private. Separarea interfeței de implementare este o idee grozavă. Aceasta se numește de obicei încapsulare.

Proprietăți

Un obiect cu paranteze (...) se numește un obiect literal. Puteți plasa imediat unele proprietăți între astfel de paranteze (...). De exemplu, perechi „cheie: valoare și așa mai departe”:

permite utilizatorului = ( // un nume de obiect: „Ioan”, // prin cheie „nume” să stocheze valoarea „ Ioan" age: 30 // by key "age" store value 30 }.!}

O proprietate are o cheie (cunoscută și ca „nume” sau „identificator”) înainte de două puncte „:” și o valoare în dreapta acesteia. Obiectul utilizator are două proprietăți. Obiectul JavaScript utilizator rezultat cu două fișiere semnate etichetate „nume” și „vârstă”. Puteți adăuga, șterge și citi fișiere din acesta în orice moment. Valorile proprietăților sunt accesate folosind notația cu puncte. Poate fi de orice tip. Puteți adăuga o valoare booleană. Pentru a elimina o proprietate, utilizați ștergere în cazul de eroare al unui obiect JavaScript.

Toate obiectele de eroare JavaScript sunt descendenți ai obiectului Error sau ai unui obiect moștenit:

  1. Obiectul Error de sintaxă moștenește de la obiectul Error.
  2. Eroare de analiză JSON a unui anumit tip de obiect Eroare de sintaxă.

Pentru a înțelege și mai profund modul în care aplicațiile tratează erorile JavaScript, aruncați o privire mai atentă la Airbrake JavaScript, un instrument de urmărire a erorilor pentru alerte în timp real și o perspectivă instantanee asupra a ceea ce a mers prost cu codul dvs. JavaScript.

Mesaje de eroare pe care un utilizator le poate primi înainte de a șterge un obiect JavaScript:

  1. Caracter de control greșit într-un șir literal.
  2. Caracter greșit într-un șir literal.
  3. Ieșire Unicode slabă.
  4. Personaj de evadare prost.
  5. Șir neterminat.
  6. Cod nenumeric neașteptat.
  7. Nu există numere după virgulă.
  8. Număr fracționar neterminat.
  9. Nu există numere după indicatorul de grad.
  10. Nu există numere după semnul exponentului.
  11. Partea exponențială nu are număr.
  12. Sfârșitul neașteptat al datelor.
  13. Cuvânt cheie neașteptat.
  14. Un simbol neașteptat.
  15. Sfârșitul datelor la citirea conținutului unui obiect.
  16. Numele de proprietate așteptat sau „)”.

Proprietăți de calcul

Puteți utiliza paranteze drepte într-un obiect literal. Acestea se numesc proprietăți calculate. Un exemplu este dat mai jos.

Sensul unei proprietăți calculate este simplu: înseamnă că numele proprietății trebuie luat din fructe. Deci, dacă un vizitator introduce „măr”, punga va deveni (măr: 5). Puteți folosi expresii mai complexe între paranteze drepte:

lasă fructe = „măr”;

: 5 // bag.appleComputers = 5

Parantezele pătrate sunt mult mai puternice decât notația cu puncte. Acestea permit nume de proprietăți și variabile. Dar sunt și mai greoi de scris. Deci, de cele mai multe ori, când numele proprietăților sunt cunoscute și simple, se folosește un punct. Și dacă aveți nevoie de ceva mai complex, atunci treceți la paranteze drepte.

Rezervarea cuvintelor

O variabilă nu poate avea un nume egal cu unul dintre cuvintele rezervate, cum ar fi „pentru”, „lasă”, „întoarce”, etc. Dar atunci când sortați obiecte JavaScript, nu există o astfel de restricție.


În principiu, orice nume este permis, dar există unul special: „__proto__” primește un tratament special din motive istorice. De exemplu, nu îl puteți seta la o altă valoare decât un obiect:

obj.__proto__ = 5;

alert(obj.__proto__); // nu a funcționat conform intenției

După cum puteți vedea din cod, scopul primitivei 5 este ignorat. Aceasta poate fi o sursă de erori și chiar vulnerabilități dacă operatorul intenționează să stocheze perechi cheie-valoare arbitrare într-un obiect și să permită vizitatorului să specifice cheile. În acest caz, vizitatorul poate selecta „proto” ca cheie și poate adăuga JavaScript la obiect. Există o modalitate de a face obiecte tratate cu __proto__ ca o proprietate obișnuită. Există, de asemenea, o altă hartă a structurilor de date care acceptă chei arbitrare.

Proprietăți întregi

Termenul „proprietate întreg” înseamnă aici un șir care poate fi convertit dintr-un număr întreg fără modificare. Deci, de exemplu, „49” este un nume de proprietate întreg, deoarece atunci când este convertit într-un număr întreg și înapoi, este în continuare același. Dar „+49” și „1,2” nu sunt așa. Pe de altă parte, dacă cheile nu sunt întregi, atunci ele sunt listate în ordinea în care au fost create. Exemplu de mai jos.


Pentru a remedia problema cu codurile de apelare, puteți „trișa” făcând codurile incomplete. Adăugarea unui „+” (semnul plus) înainte de fiecare cod este suficientă. Acum va funcționa conform intenției.

Diferența dintre obiecte și primitive este că acestea sunt stocate și copiate „prin referință”. Valorile primitive sunt atribuite și copiate „ca valoare întreagă”. O variabilă stochează o „adresă în memorie” mai degrabă decât obiectul în sine sau o „referință” la acesta. Puteți utiliza orice variabilă pentru a accesa și modifica conținutul acesteia.


Exemplul de mai sus arată că există un singur obiect și un administrator care să se conecteze la el. Apoi, dacă o cheie diferită (utilizator) este folosită ulterior, utilizatorul va observa modificările.

Operatorii de egalitate == și egalitatea strictă === pentru obiecte funcționează în același mod. Două obiecte sunt egale numai dacă sunt același obiect. Pentru comparații precum obj1 > obj2 sau comparații cu primitivul obj == 5, obiectele sunt convertite în primitive. Sincer să fiu, astfel de comparații sunt foarte rar necesare și sunt de obicei rezultatul unei erori de codare.

Validare obiect JavaScript

Obiectele au acces la orice proprietate. Totuși, dacă nu există deloc, nu va fi o eroare. Doar accesarea unei proprietăți inexistente returnează nedefinit. Oferă o modalitate foarte comună de a testa o proprietate și de a o compara cu una nedefinită. Mai jos este un exemplu.


Folosind „în” pentru proprietățile care stochează nedefinit. De obicei, o verificare strictă de comparație „=== nedefinit” funcționează bine. Mânca un caz special când eșuează și „în” funcționează corect. Acesta este momentul în care o proprietate a unui obiect există, dar rămâne nedefinită.


În codul de mai sus, proprietatea obj.test există din punct de vedere tehnic. Prin urmare, operatorul de intrare funcționează corect. Situații similare se întâmplă foarte rar deoarece undefined nu este de obicei atribuit. În cea mai mare parte, sunt utilizate valori „necunoscute” sau „vide” nule. Astfel, operatorul in este efectiv un invitat în cod.

buclă „for..in”.

Pentru a trece prin toate tastele de la obiect la obiect, există o formă specială de buclă: for..in. Acesta este un lucru complet diferit de constructul for(;;).

Mai jos este un exemplu.


Vă rugăm să rețineți că toți constructorii „for” vă permit să declarați o variabilă de buclă în interiorul unei bucle ca o cheie let. Alternativ, puteți utiliza un alt nume de variabilă, cheie.

De exemplu, for(let prop in obj) este, de asemenea, utilizat pe scară largă.

Există o alternativă „paranteză pătrată” care funcționează cu orice șir.


Ideea aici necesită ca cheile obiectului JavaScript să fie un identificator de variabilă valid, ceea ce înseamnă că nu există spații sau alte restricții. Trebuie avut grijă să vă asigurați că linia din interiorul parantezelor este citată corect. Parantezele pătrate oferă, de asemenea, o modalitate de a obține numele proprietății din rezultatul oricărei expresii, spre deosebire de un șir literal dintr-o variabilă:

let key = „îi plac păsările”;

// la fel ca user["like birds"] = true;

utilizator = adevărat.

Aici variabila cheie poate fi calculată în timpul execuției și depinde de intrarea utilizatorului și apoi utilizată pentru a accesa proprietatea. Acest lucru oferă programatorilor mai multă flexibilitate. Notația cu puncte nu poate fi utilizată într-un mod similar, deoarece ar repeta peste obiectul JavaScript. Mai jos este un exemplu.


Const obiect

Un obiect const declarat poate fi modificat. Un exemplu este dat mai jos.


Ar putea părea că obiectul JavaScript din linia (*) ar arunca o eroare, dar nu este cazul. Acest lucru se datorează faptului că const captează valoarea utilizatorului însuși. Și aici utilizatorul păstrează o referință la același obiect tot timpul. Linia (*) intră în interiorul obiectului, nu este reatribuită utilizatorului. Const va da o eroare dacă încercați să setați utilizatorul și altceva. Clonarea și fuzionarea, Object.assign creează o altă referință la același obiect dacă trebuie duplicat. Acest lucru este, de asemenea, realizabil, dar puțin mai dificil, deoarece JavaScript nu are o metodă încorporată. De fapt, acest lucru este rareori necesar. Copierea prin referință este utilizată în majoritatea cazurilor. Dar dacă chiar aveți nevoie de acest lucru, atunci trebuie să creați un obiect JavaScript și să replicați structura unuia existent, copierea proprietăților acestuia la un nivel primitiv. Mai jos este un exemplu.


Și puteți folosi și metoda Object.assign pentru aceasta. Argumentele dest și src1, ..., srcN sunt obiecte. Copiază proprietățile tuturor obiectelor src1, ..., srcNINTO dest. Cu alte cuvinte, proprietățile tuturor argumentelor, începând de la al doilea, sunt copiate în primul. Apoi se întoarce în dest. De exemplu, îl puteți folosi pentru a combina mai multe obiecte într-unul singur.


Și puteți utiliza, de asemenea, Object.assign pentru a înlocui bucla simplă de clonare. Copiază toate proprietățile utilizatorului într-un obiect gol și îl returnează, la fel ca o buclă, dar mai scurtă. Până acum, s-a presupus că toate proprietățile utilizatorului sunt primitive. Dar proprietățile pot fi referințe la alte obiecte.

Pentru a remedia acest lucru, trebuie să utilizați o buclă de clonare care verifică fiecare valoare de utilizator și, dacă este un obiect, apoi îi reproduce structura. Aceasta se numește „clonare profundă”.

Există un algoritm standard de clonare profundă care se ocupă de cazul de mai sus și de cazuri mai complexe numite algoritm de clonare structurată. Pentru a evita reinventarea roții, puteți folosi o implementare funcțională din biblioteca JavaScript lodash, metoda se numește _.cloneDeep(obj).

Metode avansate

Dacă un programator trece peste un obiect și dorește să obțină toate proprietățile în aceeași ordine în care au fost adăugate, el se poate baza pe „ordonare specială”, în care proprietățile întregi sunt sortate și altele sunt formate în ordinea în care a fost creat obiectul JavaScript. .

Metodele avansate de obiecte se ocupă de concepte care sunt rareori utilizate în JavaScript. Acest lucru se datorează faptului că, în scenariile normale, aceste caracteristici puternice nu sunt necesare. Este posibil ca unele dintre aceste metode să nu funcționeze în browserele mai vechi, cum ar fi versiunile timpurii ale Netscape 4.

Prototipul ar putea fi folosit pentru a crea obiecte JavaScript și toate metodele mycircle, nu doar pe cele noi. Acest lucru are un impact mixt asupra performanței. Nu trebuie să stocheze copii separate ale metodelor pentru fiecare instanță de obiect, așa că ar putea necesita mai puțină memorie pentru a funcționa, dar browserul trebuie să caute domeniile actuale și părinte pentru a le găsi. Acest lucru poate duce la o latență extremă. În general, utilizatorul ar trebui să folosească ceea ce este adecvat pentru cod, mai degrabă decât să bazeze acea decizie pe performanță, cu excepția cazului în care are de-a face cu un mediu controlat foarte specific.


Returnează adevărat

În unele cazuri, poate fi necesar ca proprietatea unui obiect să fie legată de obiectul în sine sau de undeva în lanțul de prototipuri. În JavaScript, toate obiectele folosesc metoda hasOwnProperty, care returnează adevărat dacă acea proprietate este legată de o instanță a unui obiect individual. În acest caz, devine posibil să se verifice dacă constructorul unui obiect are aceeași proprietate cu aceeași valoare ca și instanța obiectului în sine. Acest lucru poate da rezultate incorecte dacă există proprietăți separate ale obiectului JavaScript cu aceeași valoare atât pentru instanța obiectului, cât și pentru prototipul circuitului. Metoda hasOwnProperty ia un singur parametru - numele proprietății ca șir.


Puteți crea metode private într-un mod similar. Este pur și simplu o funcție care este creată în interiorul unei funcții de constructor. Acest lucru poate părea confuz pentru unii, dar așa funcționează. O funcție privată poate fi apelată doar de către constructorul însuși sau prin metode care sunt definite pe linie. Ele pot fi folosite ca metode publice dacă sunt atribuite unui constructor public și accesate folosind metode publice ale obiectelor Javascript.

function myob() ( function cantBeSeen() ( alert(secretValue);

) var secretValue = "";

this.method1 = function () ( secretValue = " fara surprize";!}

this.method2 = cantBeSeen;

) var oneOb = new myob();

oneOb.method1();

//alertează „fără surprize” oneOb.method2();

//avertizează „fără surprize”.

Șablon de comandă

Obiectele de comandă permit sistemele slab cuplate prin separarea celor care emit o solicitare de obiecte și a celor care procesează efectiv cererea. Aceste cereri se numesc evenimente, iar codul care procesează cererile se numește handler de evenimente.

Să presupunem că creați aplicații care acceptă acțiunile din clipboard Cut, Copy and Paste. Aceste acțiuni pot fi declanșate în diferite moduri de-a lungul aplicației: prin sistemul de meniu, prin meniul contextual, de exemplu făcând clic dreapta pe câmp de text sau o comandă rapidă de la tastatură. Obiectele de comandă vă permit să centralizați procesarea acestor acțiuni, câte una pentru fiecare operație, când este necesară o singură comandă pentru a procesa toate cererile Cut, una pentru toate cererile Copy și una pentru toate cererile Paste.

Deoarece echipele centralizează toată procesarea, ele sunt adesea implicate în gestionarea funcțiilor de anulare pentru întreaga aplicație. Îmbunătățiri semnificative pot fi obținute prin utilizarea metode moderne JavaScript, rezultând aplicații mai eficiente, mai fiabile și mai ușor de întreținut.

Pentru a afla cum să faceți acest lucru, puteți utiliza șabloane JavaScript + jQuery. Acest pachet unic include JavaScript optimizat pentru toate șabloanele GoF folosind funcții mai avansate, cum ar fi spații de nume, prototipuri, module, obiecte funcționale, închideri, funcții anonime și multe altele. Dacă utilizatorii au nevoie de cele mai recente instrumente și tehnici pentru șabloanele JavaScript, șabloanele jQuery și arhitecturile de șabloane, atunci acesta este cel mai bun caz de utilizare. Acest pachet conține informații valoroase și actualizate pentru dezvoltatorii JavaScript. Iată ce este inclus:

  1. Șabloane GoF optimizate pentru JavaScript.
  2. Modele moderne de design JavaScript.
  3. Model-View Design Patterns.
  4. Șabloane de design jQuery.
  5. Modele arhitecturale ale idiomurilor JavaScript.
  6. Exemple de aplicații (MVC, SPA etc.)

Elementele de bază propuse pentru sintaxa obiectelor JavaScript sunt foarte importante pentru programatorii începători. Mai întâi trebuie să înțelegem obiectele, apoi vor exista cunoștințe despre programarea orientată pe obiecte. Este esențial să aveți o înțelegere profundă a acestui material, deoarece servește drept bază pentru restul limbajului JavaScript.

JavaScript este conceput pe baza unei paradigme simple. Conceptul se bazează pe obiecte simple. Un obiect este o colecție de proprietăți, iar fiecare proprietate constă dintr-un nume și o valoare asociate cu acel nume. Valoarea proprietății poate fi o funcție, care poate fi apelată metodă obiect. Pe lângă obiectele încorporate în browser, vă puteți defini propriile obiecte. Acest capitol descrie cum să utilizați obiecte, proprietăți, funcții și metode și cum să vă creați propriile obiecte.

Privire de ansamblu asupra obiectelor

Obiectele din JavaScript, ca și în multe alte limbaje de programare, sunt similare cu obiectele viata reala. Conceptul de obiecte JavaScript este mai ușor de înțeles prin realizarea de paralele cu obiectele din viața reală.

În JavaScript, un obiect este o unitate independentă care are proprietăți și un anumit tip. Să comparăm, de exemplu, cu o cană. O ceașcă are culoare, formă, greutate, material din care este făcută etc. La fel, obiectele JavaScript au proprietăți care le definesc caracteristicile.

Obiecte și proprietăți

În JavaScript, un obiect are proprietăți asociate cu el. O proprietate de obiect poate fi înțeleasă ca o variabilă atribuită unui obiect. Proprietățile obiectului sunt în esență aceleași cu variabilele JavaScript, cu excepția faptului că sunt atribuite obiectului. Proprietățile unui obiect determină caracteristicile acestuia. Puteți accesa o proprietate a unui obiect folosind notația cu puncte:

ObjectName.propertyName

La fel ca toate variabilele JavaScript, numele obiectului (care poate fi și o variabilă) și numele proprietății sunt sensibile la majuscule și minuscule. Puteți defini o proprietate specificând valoarea acesteia. De exemplu, să creăm un obiect myCar și să definim proprietățile marca, modelul și anul, după cum urmează:

Var myCar = obiect nou(); myCar.make = „Ford”; myCar.model = „Mustang”; myCar.year = 1969;

Proprietățile obiectelor nedefinite sunt nedefinite (nu nule).

Mașina mea. culoare; // nedefinit

Proprietățile obiectelor JavaScript pot fi, de asemenea, accesate sau setate folosind notația paranteze (a se vedea pentru mai multe detalii). Obiectele sunt uneori numite tablouri asociative, deoarece fiecare proprietate este asociată cu o valoare șir care poate fi folosită pentru a o accesa. Deci, de exemplu, puteți accesa proprietățile obiectului myCar astfel:

MyCar["make"] = "Ford"; myCar["model"] = "Mustang"; myCar["anul"] = 1969;

Numele proprietăților obiectelor pot fi șiruri JavaScript sau orice poate fi convertit într-un șir, inclusiv șirul gol. Cu toate acestea, orice nume de proprietate care conține un identificator JavaScript nevalid (de exemplu, un nume de proprietate care conține un spațiu și o liniuță sau care începe cu un număr) poate fi accesat folosind paranteze drepte. Această notație este utilă și atunci când numele proprietăților trebuie să fie determinate dinamic (când numele proprietății nu este determinat până la runtime). Exemple de mai jos:

Var myObj = new Object(), str = "myString", rand = Math.random(), obj = new Object(); myObj.type = "Sintaxa punctului"; myObj["date created"] = "Șir cu spațiu"; myObj = „Valoare șir”; myObj = „Număr aleatoriu”; myObj = „Obiect”; myObj[""] = "Chiar și un șir gol"; console.log(myObj);

Rețineți că toate cheile cu paranteze drepte sunt convertite într-un tip String, deoarece obiectele din JavaScript pot avea doar un tip String ca cheie. De exemplu, în codul de mai sus, când cheia obj este adăugată la myObj , JavaScript apelează metoda obj.toString() și folosește acel șir rezultat ca nouă cheie.

De asemenea, puteți accesa proprietăți folosind o valoare șir care este stocată într-o variabilă:

Var propertyName = "facă"; myCar = "Ford"; propertyName = "model"; myCar = „Mustang”;

Puteți folosi paranteze pătrate într-o clauză for...in pentru a itera toate proprietățile unui obiect pentru care este permis. Pentru a arăta cum funcționează, următoarea funcție arată toate proprietățile unui obiect atunci când treceți obiectul în sine și numele acestuia ca argumente funcției:

Funcția showProps(obj, objName) ( var rezultat = ""; pentru (var i în obj) ( if (obj.hasOwnProperty(i)) (rezultat += objName + "." + i + " = " + obj[i ] + „\n”; ) ) returnează rezultatul; )

Deci, dacă numim această funcție astfel showProps(myCar, "myCar"), vom obține rezultatul:

MyCar.make = Ford myCar.model = Mustang myCar.year = 1969

Listarea tuturor proprietăților unui obiect

Folosind funcția constructor

O altă modalitate de a crea un obiect în doi pași este descrisă mai jos:

  1. Determinați tipul unui obiect scriind o funcție de constructor. Numele unei astfel de funcții începe de obicei cu o literă mare.
  2. Creați o instanță a unui obiect folosind cuvântul cheie nou.

Pentru a determina tipul unui obiect, creați o funcție care determină tipul obiectului, numele, proprietățile și metodele acestuia. De exemplu, să presupunem că doriți să creați un tip de obiect pentru a descrie mașinile. Doriți ca un obiect de acest tip să se numească mașină și doriți să aibă proprietățile marca, modelul și anul. Pentru a face acest lucru, scrieți următoarea funcție:

Funcția Mașină (marcă, model, an) ( this.make = make; this.model = model; this.year = year; )

Rețineți că aceasta este folosită pentru a atribui valori (transmise ca argumente de funcție) proprietăților unui obiect.

Acum puteți crea un obiect numit mycar astfel:

Var mycar = masina noua("Eagle", "Talon TSi", 1993);

Această declarație creează un obiect de tip Car cu referință mycar și atribuie anumite valori proprietățile sale. Valoarea mycar.make va fi șirul „Eagle”, mycar.year va fi numărul întreg 1993 și așa mai departe.

Puteți crea câte obiecte mașină aveți nevoie, apelând pur și simplu nou. De exemplu:

Var kenscar = mașină nouă ("Nissan", "300ZX", 1992); var vpgscar = masina noua("Mazda", "Miata", 1990);

Un obiect poate avea o proprietate care va fi un alt obiect. De exemplu, următoarele definește un obiect de tip Persoană după cum urmează:

Funcție Persoană (nume, vârstă, sex) ( this.name = nume; this.age = vârstă; this.sex = sex; )

și apoi creați două noi instanțe de obiect Person, după cum urmează:

Var rand = new Person("Rand McKinnon", 33, "M"); var ken = new Person("Ken Jones", 39, "M");

Apoi, puteți rescrie definiția mașinii pentru a include o proprietate a proprietarului, căruia i se atribuie un obiect persoană, astfel:

Funcția Mașină (marcă, model, an, proprietar) ( this.make = make; this.model = model; this.year = year; this.owner = proprietar; )

Apoi, pentru a instanția noile obiecte, urmați aceste instrucțiuni:

Var car1 = new Car("Vultur", "Talon TSi", 1993, rand); var car2 = new Car("Nissan", "300ZX", 1992, ken);

Rețineți că, în loc să transmiteți un șir, un literal sau un întreg atunci când creați obiecte noi, expresiile de mai sus transmit obiecte rand și ken ca argumente pentru funcție. Acum, dacă trebuie să aflați numele proprietarului car2, puteți face acest lucru:

Car2.proprietar

Rețineți că oricând puteți adăuga o nouă proprietate unui obiect creat anterior. De exemplu, expresia

Car1.color = „negru”;

adaugă o proprietate de culoare la car1 și își setează valoarea la „negru”. Cu toate acestea, acest lucru nu afectează niciun alt obiect. Pentru a adăuga o nouă proprietate la toate obiectele de același tip, trebuie să adăugați proprietatea la definiția tipului obiectului mașină.

Folosind metoda Object.create

Obiectele pot fi create și folosind metoda Object.create. Această metodă este foarte convenabilă deoarece vă permite să specificați un obiect prototip pentru un nou obiect al dvs. fără a defini o funcție de constructor.

// lista de proprietăți și metode pentru Animal var Animal = ( tip: "Nevertebrate", // Valoarea implicită de tip displayType: function() ( // Metodă de afișare a tipului obiectului Animal console.log(this.type); )); // Creați un obiect Animal var animal1 = Object.create(Animal); animal1.displayType(); // Ieșiri: Nevertebrate // Creați un obiect Animal și atribuiți-i tip = Fishes var fish = Object.create(Animal); fish.type = „Pești”; fish.displayType(); // Ieșiri: Pești

Moştenire

Toate obiectele din JavaScript moștenesc de la cel puțin alt obiect. Obiectul de la care a avut loc moștenirea se numește prototip, iar proprietățile moștenite pot fi găsite în obiectul prototip al constructorului.

Indici de proprietate a obiectelor

În JavaScript 1.0, vă puteți referi la proprietățile unui obiect fie prin numele său, fie prin indexul său ordinal. În JavaScript 1.1 și versiunile ulterioare, dacă ați definit inițial o proprietate după nume, trebuie întotdeauna să vă referiți la ea prin numele ei, iar dacă ați definit inițial o proprietate după index, trebuie să vă referiți la ea prin indexul său.

Această limitare este impusă atunci când creați un obiect și proprietățile acestuia folosind funcția de constructor (cum am făcut mai devreme cu tipul Mașină) și când definiți proprietățile individuale în mod explicit (de exemplu, myCar.color="red"). Dacă ați definit inițial o proprietate a unui obiect printr-un index, de exemplu myCar = "25 mpg" , atunci vă puteți referi ulterior la această proprietate numai ca myCar .

Excepția de la regulă o reprezintă obiectele redate din HTML, cum ar fi matricea de formulare. Vă puteți referi oricând la obiectele din aceste matrice, fie folosind indexul lor (care se bazează pe ordinea în care apar document HTML), sau după numele lor (dacă acestea au fost identificate). De exemplu, dacă a doua etichetă html

într-un document are o valoare a atributului NAME „myForm”, puteți face referire la acel formular astfel: document.forms sau document.forms[“myForm”] sau document.myForm .

Definirea proprietăților pentru un tip de obiect

Puteți adăuga o proprietate la un tip de obiect definit anterior folosind proprietatea specială prototip. Folosind prototip, este creată o proprietate care este aceeași pentru toate obiectele de acest tip, mai degrabă decât o singură instanță a acelui tip de obiect. Următorul cod demonstrează acest lucru prin adăugarea unei proprietăți de culoare la toate obiectele de tip car și apoi atribuirea unei valori proprietății de culoare a obiectului car1.

Car.prototype.color = null; car1.color = „negru”;

Codul de mai jos arată cum puteți utiliza un getter și setter pentru a extinde prototipul obiectului Date și pentru a adăuga o proprietate year la acesta, care va funcționa pentru toate instanțele clasei Date. Acest cod folosește metode existente Clasa de date - getFullYear și setFullYear pentru operarea getter și setter.

Definirea unui getter și setter pentru proprietatea year:

Var d = Data.prototip; Object.defineProperty(d, „an”, ( get: function() ( return this.getFullYear(); ), set: function(y) ( this.setFullYear(y); ) ));

Folosind proprietatea year specificată de un getter și setter:

Var acum = data noua(); console.log(acum.an); // 2000 acum.an = 2001; // 987617605170 console.log(acum); // Miercuri, 18 aprilie 11:13:25 GMT-0700 (Ora de vară a Pacificului) 2001

Practic, getters și setters pot fi fie:

Când definiți un getter și setter folosind , tot ce trebuie să faceți este să prefixați getter-ul cu get și setter-ul cu set . În acest caz, metoda getter nu ar trebui să aștepte niciun parametru, în timp ce metoda setter ia un singur parametru (noua valoare de atribuit proprietății). De exemplu:

Var o = ( a: 7, get b() ( return this.a + 1; ), set c(x) ( this.a = x / 2; ) );

Getters și setters pot fi adăugați la un obiect existent în orice moment folosind metoda Object.defineProperties. Primul parametru al acestei metode este obiectul căruia doriți să îi atribuiți getter-ul și setter-ul. Al doilea parametru este un obiect ale cărui nume de proprietate vor corespunde numelor proprietăților create, iar valorile sunt obiecte care definesc getter-ul și setter-ul proprietăților create. Următorul exemplu creează exact același getter și setter ca exemplul de mai sus:

Var o = ( a: 0 ); Object.defineProperties(o, ( "b": ( get: function() ( return this.a + 1; ) ), "c": ( set: function(x) ( this.a = x / 2; ) ) )); o.c = 10; // Rulează un setter care atribuie 10 / 2 (5) proprietății „a” console.log(o.b); // Declanșează un getter care returnează un + 1 (adică 6)

Care dintre cele două forme pe care le utilizați pentru a defini proprietăți depinde de stilul dvs. de programare și de sarcina la îndemână. Dacă utilizați deja un inițializator de obiect pentru a defini un prototip, probabil că veți folosi prima formă în majoritatea cazurilor. Este mai compact și mai natural. Cu toate acestea, nu este neobișnuit ca a doua formă să fie singura posibilă în cazurile în care lucrați cu un obiect existent fără acces la definiția acestuia. A doua formă reflectă cel mai bine natura dinamică a JavaScript - dar poate face codul dificil de citit și de înțeles.

Îndepărtarea proprietăților

Puteți șterge o proprietate folosind operatorul de ștergere. Următorul cod arată cum să eliminați o proprietate.

//Creează un nou obiect, myobj, cu două proprietăți, a și b. var myobj = obiect nou; myobj.a = 5; myobj.b = 12; //Elimină proprietatea a, lăsând myobj doar proprietatea b. sterge myobj.a;

De asemenea, puteți utiliza ștergerea pentru a elimina o variabilă globală dacă cuvântul cheie var nu a fost folosit când ați declarat-o:

G = 17; șterge g;

  • Pentru studiu detaliat citit .
  • Pentru a afla despre clasele ECMAScript 2015 (noul mod de a defini obiecte), citiți capitolul.

Obiecte

Object este un tip de date fundamental în limbajul JavaScript. Un obiect este o valoare compusă: combină un set de valori (valori simple sau alte obiecte) și permite ca acele valori să fie stocate și preluate după nume.

Un obiect este o colecție neordonată de proprietăți, fiecare având un nume și o valoare. Numele proprietăților sunt șiruri de caractere, așa că se poate spune că obiectele mapează șiruri de caractere la valori. Această mapare a șirurilor de caractere la valori poate avea mai multe nume: este posibil să fiți deja familiarizați cu o structură fundamentală de date, cum ar fi un hash, un dicționar sau o matrice asociativă. Cu toate acestea, la un obiect există mai mult decât o simplă mapare a șirurilor de caractere la valori.

Pe lângă propriile proprietăți, obiectele JavaScript pot moșteni și proprietăți de la alte obiecte, cunoscute sub numele de prototipuri. Metodele obiect sunt reprezentanți tipici ai proprietăților moștenite și „ moștenire prin prototipuri" este caracteristica cheie limbaj JavaScript.

Obiectele din JavaScript sunt dinamice - de obicei vă permit să adăugați și să eliminați proprietăți - dar pot fi folosite și pentru a emula obiectele și „structurile” statice găsite în limbajele de programare JavaScript. sistem static tipuri. Ele pot fi, de asemenea, folosite (dacă ignorați că obiectele mapează șiruri la valori) pentru a reprezenta seturi de șiruri.

Orice valoare din JavaScript care nu este un șir, număr, adevărat, fals, nul sau nedefinit este un obiect. Și chiar și șirurile de caractere, numerele și booleanele care nu sunt obiecte se pot comporta ca obiecte imuabile (au obiecte de tip String, Number etc.).

Obiectele sunt valori modificabile iar operatiile asupra acestora se fac prin referinta, nu dupa valoare. Dacă variabila x se referă la un obiect și afirmația var y = x; , variabila y va conține o referință la același obiect, nu o copie a acestuia. Orice modificări aduse obiectului de variabila y se vor reflecta și în variabila x.

O proprietate are un nume și o valoare. Numele proprietății poate fi orice șir, inclusiv șirul gol, dar un obiect nu poate avea două proprietăți cu același nume. Valoarea proprietății poate fi orice valoare permisă în limbajul JavaScript sau (în ECMAScript 5) o funcție de citire sau scriere (sau ambele).

Pe lângă nume și valori, fiecare proprietate are un număr de valori asociate cu ea, numite atribute de proprietate :

    Atribut inscriptibil determină dacă valoarea unei proprietăți poate fi scrisă.

    Atribut enumerabil determină dacă numele proprietății este disponibil pentru enumerare într-o buclă for/in.

    Atribut configurabil determină posibilitatea personalizării, adică ștergerea unei proprietăți și modificarea atributelor acesteia.

Înainte de apariția standardului ECMAScript 5, toate proprietățile din obiecte creat de program, disponibil pentru înregistrare, listare și personalizare. ECMAScript 5 oferă posibilitatea de a personaliza atributele proprietăților dvs.

Pe lângă proprietăți, fiecare obiect are trei atributul obiectului :

    Atribut clasă conține un șir cu numele clasei obiectului și specifică tipul obiectului.

    Steag extensibil(în ECMAScript 5) indică capacitatea de a adăuga noi proprietăți unui obiect.

În cele din urmă, mai jos este o descriere a unor termeni care ne vor ajuta să distingem între cele trei categorii largi de obiecte din JavaScript și cele două tipuri de proprietăți:

Obiect limbaj de bază

Este un obiect sau o clasă de obiecte definită de specificația ECMAScript. Matricele, funcțiile, datele și expresiile regulate (de exemplu) sunt obiecte de bază ale limbajului.

Obiect de rulare

Acesta este un obiect definit de mediul de rulare (cum ar fi un browser web) în care este încorporat interpretul JavaScript. Obiectele HTMLElement, care reprezintă structura unei pagini web în JavaScript pe partea clientului, sunt obiecte de rulare. Obiectele runtime pot fi, de asemenea, obiecte limbaj de bază, de exemplu atunci când runtime definește metode care sunt obiecte Function obișnuite ale limbajului JavaScript de bază.

Obiect personalizat

Orice obiect creat prin executarea codului JavaScript.

Proprietate proprie

Aceasta este o proprietate definită direct pe un obiect dat.

Proprietate moștenită

Aceasta este o proprietate definită de prototipul obiectului.

Crearea obiectelor

Obiectele pot fi create folosind literalmente obiect, noul cuvânt cheie și (în ECMAScript 5) funcții Object.create().

Literale obiect

Cel mai simplu mod de a crea un obiect este să includeți un obiect literal în programul dvs. Un obiect literal este o listă de proprietăți separate prin virgulă (perechi nume/valoare) închisă între acolade. Numele proprietății poate fi un identificator sau un șir literal (șirul gol este acceptabil). Valoarea unei proprietăți poate fi orice expresie permisă în JavaScript - valoarea expresiei (aceasta poate fi o valoare simplă sau un obiect) va deveni valoarea proprietății.

Mai jos sunt câteva exemple de creare a obiectelor:

Var gol = (); // Obiect fără proprietăți var point = ( x:0, y:0 ); // Două proprietăți var point2 = ( x:punct.x, y:punct.y+1 ); // Valori mai complexe ​​var site = ( "url site": "www..NET Framework", // și cratime, deci folosiți ghilimele autor: ( // Valoarea acestei proprietăți este prenume: "Alexandr", / / obiect. Vă rugăm să rețineți că numele de familie: „Frolov” // numele acestor proprietăți sunt fără ghilimele. ) );

ECMAScript 5 (și unele implementări ale ECMAScript 3) permite cuvintelor rezervate să fie folosite ca nume de proprietăți fără ghilimele. Cu toate acestea, în general, numele de proprietăți care se potrivesc cu cuvintele rezervate din ECMA-Script 3 trebuie să fie cuprinse între ghilimele. În ECMAScript 5, ultima virgulă după ultima proprietate dintr-un literal obiect este ignorată. Majoritatea implementărilor ECMAScript 3 ignoră, de asemenea, virgulele de sfârșit, dar IE interpretează prezența lor ca o eroare.

Un obiect literal este o expresie care creează și inițializează un nou obiect ori de câte ori acea expresie este evaluată. Valoarea fiecărei proprietăți este recalculată atunci când este evaluată valoarea literalului. Aceasta înseamnă că un singur obiect literal poate crea multe obiecte noi dacă literalul este plasat în corpul unei bucle sau funcție care va fi apelată în mod repetat și că valorile proprietăților acestor obiecte pot diferi unele de altele.

Crearea de obiecte folosind noul operator

Noul operator creează și inițializează un nou obiect. Această declarație trebuie să fie urmată de numele funcției. O funcție folosită în acest fel se numește constructor și servește la inițializarea noului creat a acestui obiect. JavaScript de bază include mulți constructori încorporați pentru crearea obiectelor limbajului de bază. De exemplu:

Var o = obiect nou(); // Creați un nou obiect gol: la fel ca () var a = new Array(); // Creați o matrice goală: la fel ca var d = new Date(); // Creați un obiect Date reprezentând ora curentă var r = new RegExp("js"); // Creați un obiect RegExp pentru operațiunile de potrivire a modelelor

În plus față de acești constructori încorporați, este posibil să definiți propriile funcții de constructor pentru a inițializa obiectele nou create. Cum se face acest lucru este descris în articolul următor.

Object.create()

Standardul ECMAScript 5 definește metoda Object.create(), care creează un nou obiect și folosește primul său argument ca prototip al acelui obiect. În plus, Object.create() poate lua un al doilea argument opțional care descrie proprietățile noului obiect.

Object.create() este o funcție statică, nu o metodă numită pe un anumit obiect. Pentru a apela această funcție, trebuie doar să îi transmiteți obiectul prototip dorit:

// obj moștenește proprietățile x și y var obj = Object.create((x:1, y:2));

Pentru a crea un obiect care nu are prototip, puteți trece null, dar în acest caz obiectul nou creat nu va moșteni nicio proprietate sau metode de bază, cum ar fi toString() (ceea ce înseamnă că acest obiect nu poate fi folosit în expresii cu operator +) :

// obj2 nu moștenește nicio proprietate sau metodă var obj2 = Object.create(null);

Dacă programul dvs. trebuie să creeze un obiect gol obișnuit (așa cum este returnat de o expresie literal() sau o nouă expresie Object(), transmite Object.prototype ca prim argument:

// obj3 este ca un obiect creat // folosind () sau nou Object() var obj3 = Object.create(Object.prototype);

Capacitatea de a crea obiecte noi cu prototipuri arbitrare (să spunem altfel: abilitatea de a crea „moștenitori” din orice obiecte) este un instrument puternic care poate fi simulat în ECMAScript 3 folosind funcția prezentată în exemplul de mai jos:

// inherit() returnează un obiect nou creat care moștenește proprietățile // obiectului prototip p. Utilizează funcția ECMAScript 5 Object.create() // dacă este definită, în caz contrar folosește o tehnică mai veche. funcția moștenire(p) (dacă (p == null) aruncă TypeError(); // p nu poate fi nulă dacă (Object.create) // Dacă Object.create() este definit... return Object.create(p ) ; // folosiți-l. var t = tipul p; // În caz contrar, aflați tipul și verificați-l dacă (t !== „obiect” && t !== „funcție”) aruncă TypeError(); funcția f() () ; // Definiți un constructor gol. f.prototype = p; // Setați proprietatea de prototip // la o referință la obiectul p. return new f(); // Folosiți f() pentru a crea // " succesorul" obiectului p. )

Implementarea funcției inherit() va avea mai mult sens odată ce vom cunoaște constructorii în articolul următor. Pentru moment, presupuneți doar că returnează un nou obiect care moștenește proprietățile obiectului din argument. Rețineți că inherit() nu este un înlocuitor complet pentru Object.create(): nu vă permite să creați obiecte fără un prototip și nu necesită un al doilea argument opțional așa cum face Object.create().

Obținerea și schimbarea proprietăților

Puteți obține valoarea unei proprietăți folosind operatorii punct (.) și paranteze pătrate (). În stânga operatorului trebuie să existe o expresie care returnează un obiect. Când utilizați operatorul punct, în dreapta ar trebui să existe un identificator simplu care să se potrivească cu numele proprietății. Când utilizați paranteze pătrate, parantezele pătrate trebuie să includă o expresie care returnează un șir care conține numele proprietății dorite:

// Obiect simplu var user = ( login:"kot86", nume:"Alexandr", varsta:26); var login = user.login; // Obține proprietatea „login” a obiectului utilizator var name = user.name; // Obține proprietatea „nume” a obiectului utilizator var age = user[„varsta”]; // Obține proprietatea „vârstă” a obiectului utilizator

Pentru a crea o proprietate nouă sau a modifica valoarea unei proprietăți existente, se folosesc și operatorii punct și paranteze drepte, ca în operațiunile de citire a valorilor proprietăților, dar expresia însăși este plasată în stânga operatorului de atribuire:

User.age = 28; // Schimbați valoarea proprietății „age” user["login"] = "kot84"; // Schimbați valoarea proprietății "login" user["surname"] = "Frolov"; // Creați o nouă proprietate "nume"

În ECMAScript 3, un identificator care urmează unui punct nu poate fi un cuvânt rezervat: nu puteți scrie un apel de proprietate la o.for sau o.class deoarece for este un cuvânt cheie și class este un cuvânt rezervat pentru utilizare ulterioară.

Dacă un obiect are proprietăți ale căror nume se potrivesc cu cuvintele rezervate, trebuie să utilizați notația dintre paranteze drepte pentru a le accesa: o["for"] și o["class"]. Standardul ECMAScript 5 relaxează această cerință (cum o fac deja unele implementări ECMAScript 3) și permite utilizarea cuvintelor rezervate după operatorul punct.

Prototipuri

Fiecare obiect din JavaScript are un al doilea obiect (sau nul, dar mult mai rar) asociat cu el. Acest al doilea obiect se numește prototip, iar primul obiect își moștenește proprietățile de la prototip.

Toate obiectele create folosind literale obiect au același obiect prototip, care poate fi referit într-un program JavaScript ca Object.prototype .

Obiectele create folosind cuvântul cheie nou și un apel de constructor primesc valoarea proprietății prototip a funcției de constructor ca prototip. Prin urmare, un obiect creat de noua Object() moștenește proprietățile Object.prototype ca și cum ar fi fost creat folosind un literal acolade (). În mod similar, prototipul unui obiect creat de new Array() este Array.prototype, iar prototipul unui obiect creat de new Date() este Date.prototype.

Object.prototype este unul dintre puținele obiecte care nu are un prototip: nu are proprietăți moștenite. Alte obiecte prototip sunt doar obiecte obișnuite care au propriile lor prototipuri.

Toți constructorii încorporați (și majoritatea constructorilor personalizați) moștenesc prototipul Object.prototype. De exemplu, Date.prototype moștenește proprietăți de la Object.prototype, deci un obiect Date creat de new Date() moștenește proprietăți atât de la Date.prototype, cât și de la Object.prototype. O astfel de secvență conectată de obiecte prototip se numește lanț de prototipuri.

Moştenire

Obiectele din JavaScript au multe „proprietăți proprii” și pot, de asemenea, să moștenească multe proprietăți de la obiectul lor prototip. Pentru a înțelege acest lucru, trebuie să studiați cu atenție mecanismul de acces la proprietate. Exemplele din această secțiune folosesc funcția inherit() prezentată mai sus pentru a crea obiecte cu prototipuri specifice.

Să presupunem că programul accesează proprietatea x a obiectului obj. Dacă obj nu are propria sa proprietate cu acest nume, se încearcă să caute proprietatea x în prototipul lui obj. Dacă obiectul prototip nu are propria sa proprietate cu acest nume, dar are propriul prototip, se încearcă căutarea proprietății în prototipul prototipului. Aceasta continuă până când se găsește proprietatea x sau se ajunge la un obiect care nu are prototip. După cum puteți vedea, atributul prototip al unui obiect creează un lanț sau lista legată obiecte de la care sunt moștenite proprietăți.

Var obj = (); // obj moștenește metodele obiectului Object.prototype obj.x = 1; // și are propria sa proprietate x. var p = mostenire(obj); // p moștenește proprietățile obiectelor obj și Object.prototype p.y = 2; // și are proprietatea proprie y. var q = mostenire(p); // q moștenește proprietățile obiectelor p, obj și Object.prototype q.z = 3; // și are proprietatea proprie z. var s = q.toString(); // toString moștenește de la Object.prototype var d = q.x + q.y // Rezultatul 3: x și y moștenesc de la obj și p

Acum să presupunem că programul atribuie o anumită valoare proprietății x a lui obj. Dacă obj are deja propria sa proprietate (nu moștenită) numită x, atunci operația de atribuire va schimba pur și simplu valoarea proprietății existente. În caz contrar, o nouă proprietate numită x va fi creată în obj. Dacă obj a moștenit anterior proprietatea x, proprietatea moștenită va fi acum ascunsă de o proprietate nou creată proprie cu același nume.

Operația de atribuire a unei valori unei proprietăți va verifica prezența acelei proprietăți în lanțul de prototipuri pentru a se asigura că atribuirea este validă. De exemplu, dacă obiectul obj moștenește proprietatea de numai citire x, atunci atribuirea nu va avea loc. Cu toate acestea, dacă atribuirea este validă, proprietatea este întotdeauna creată sau modificată în obiectul original și niciodată în lanțul de prototipuri. Faptul că mecanismul de moștenire funcționează la citirea proprietăților, dar nu funcționează la scrierea unor valori noi, este o caracteristică cheie a limbajului JavaScript, deoarece vă permite să suprascrieți selectiv proprietățile moștenite:

Var unitcercle = (r:1); // Obiectul de la care este moștenită proprietatea var c = inherit(unitcircle); // c moștenește proprietatea r c.x = 1; c.y = 1; // c definește două proprietăți proprii c.r = 2; // c suprascrie proprietatea moștenită console.log(unitcircle.r); // => 1: obiectul prototip nu s-a schimbat

Există o excepție de la această regulă, atunci când operația de atribuire a proprietăților eșuează sau are ca rezultat crearea/modificarea unei proprietăți pe obiectul original. Dacă obj moștenește proprietatea x și acea proprietate este accesată prin accesorii, atunci în loc să creeze o nouă proprietate x pe obj, este apelată o metodă de scriere a noii valori. Totuși, rețineți că metoda de scriere este apelată pe obj, nu pe prototipul în care este definită proprietatea, deci dacă metoda de scriere definește orice proprietăți, acestea vor fi instanțiate pe obj, iar lanțul de prototipuri va rămâne din nou neschimbat.

Erori de acces la proprietate

Expresiile de acces la proprietate nu returnează întotdeauna sau modifică valoarea unei proprietăți. Această secțiune descrie situații în care operațiunile de citire sau scriere a proprietăților eșuează.

O încercare de a accesa o proprietate inexistentă nu este considerată o eroare. Dacă proprietatea x nu este găsită printre proprietățile proprii sau moștenite ale obj, expresia de acces la proprietate obj.x va returna nedefinit.

Cu toate acestea, încercarea de a accesa o proprietate a unui obiect inexistent este considerată o eroare. Valorile nule și nedefinite nu au proprietăți, iar încercările de a accesa proprietățile acestor valori sunt considerate o eroare:

// Obiect simplu var user = ( login:"kot86", nume:"Alexandr", varsta:26); var a = utilizator.parolă; // nedefinit: lipsește proprietatea // Declanșează o excepție TypeError. // Valoarea nedefinită nu are o proprietate de lungime var len = user.password.length;

Dacă nu sunteți sigur că user și user.password sunt obiecte (sau se comportă ca niște obiecte), nu ar trebui să utilizați expresia user.password.length deoarece poate crea o excepție. Următoarele demonstrează două moduri de a vă proteja împotriva acestui tip de excepție:

// Mod mai vizual și direct var len = nedefinit; if (utilizator) ( if (user.password) len = user.password.length; ) // O alternativă mai concisă, specifică JavaScript // pentru obținerea lungimii valorii proprietății parolei var len = user && user. parola && user.password.length ;

Încercarea de a seta valoarea unei proprietăți la alte valori nu are întotdeauna succes: unele proprietăți sunt doar pentru citire și nu permit modificarea valorilor lor. În plus, unele obiecte nu vă permit să adăugați noi proprietăți la ele. Cu toate acestea, cel mai interesant lucru este că astfel de eșecuri, de regulă, nu duc la ridicarea unei excepții:

// Proprietățile prototipului constructorilor încorporați sunt doar pentru citire Object.prototype = 0; // Atribuirea nu va ridica o excepție; // valoarea Object.prototype nu se va schimba

Această defecțiune istorică JavaScript este remediată în modul strict definit de standardul ECMAScript 5. Toate încercări nereușite modificarea valorii unei proprietăți în modul strict are ca rezultat o excepție TypeError.

Regulile pentru a determina când o încercare de a efectua o operațiune de atribuire va reuși și când va eșua sunt simple și directe, dar greu de exprimat într-o manieră suficient de concisă. O încercare de a atribui o valoare proprietății p a obj va eșua în următoarele cazuri:

    Obiectul obj are propria sa proprietate de numai citire p: nu puteți modifica valoarea unei proprietăți numai de citire. (Rețineți, totuși, că metoda defineProperty() este o excepție care vă permite să modificați valorile proprietăților personalizate numai pentru citire.)

    Obiectul obj are o proprietate moștenită numai în citire p: proprietățile numai în citire moștenite nu pot fi înlocuite de propriile proprietăți cu aceleași nume.

    Obiectul obj nu are proprietatea proprie p; obj nu moștenește proprietatea p cu metodele accesorii, iar atributul extensibil al lui obj este fals. Dacă proprietatea p nu este prezentă în obj și nu există nicio metodă de scriere definită pentru aceasta, atunci operația de atribuire va încerca să adauge proprietatea p la obj. Dar, deoarece obj nu este extensibil, încercarea de a adăuga o nouă proprietate la acesta va eșua.

Îndepărtarea proprietăților

Operator șterge elimină o proprietate dintr-un obiect. Singurul său operand trebuie să fie o expresie de acces la proprietate. Poate părea surprinzător, dar operatorul de ștergere nu afectează valoarea proprietății - operează pe proprietatea în sine:

// Obiect simplu var user = ( login:"kot86", nume:"Alexandr", varsta:26); șterge user.login; // Acum obiectul utilizator nu are o proprietate de conectare delete user["nume"]; // Acum obiectul utilizator nu are o proprietate de nume

Operatorul de ștergere șterge doar propriile proprietăți și nu le șterge pe cele moștenite. (Pentru a elimina o proprietate moștenită, trebuie să o eliminați din obiectul prototip în care este definită. Această operație va afecta toate obiectele care moștenesc acel prototip.)

Expresia de ștergere returnează true când proprietatea a fost ștearsă cu succes sau când operația de ștergere nu a schimbat obiectul (de exemplu, când se încearcă ștergerea unei proprietăți care nu există). Expresia de ștergere returnează, de asemenea, adevărată atunci când este transmisă o expresie care nu este o expresie de acces la proprietate:

Obj = (x:1); // obj are propria sa proprietate x și moștenește toString delete obj.x; //Șterge x și returnează true delete obj.x; //Nu face nimic (x nu există) și returnează true delete obj.toString; // Nu va face nimic (toString nu este proprietatea sa) și va returna true delete 1; // Inutil, dar va returna adevărat

Operatorul de ștergere nu șterge proprietățile neconfigurabile, atributul configurabil care are valoarea false. (Cu toate acestea, poate elimina proprietățile personalizate ale obiectelor neextensibile.) Proprietățile neconfigurabile sunt proprietăți încorporate ale obiectului, precum și proprietățile globale ale obiectelor create folosind declarații de variabile și funcții. Încercarea de a elimina o proprietate neconfigurabilă în modul strict generează o TypeError. În modul non-strict (și în implementările ECMAScript 3), operatorul de ștergere returnează pur și simplu false în astfel de cazuri:

Șterge Object.prototype; // Eliminarea nu este posibilă - proprietatea neconfigurabilă var x = 1; // Declararea unei variabile globale delete this.x; // Această proprietate nu poate fi ștearsă funcția f() () // Declarație globală a funcției delete this.f; // Nici această proprietate nu poate fi ștearsă

Verificarea existentei proprietatilor

Obiectele din JavaScript pot fi gândite ca seturi de proprietăți și este adesea util să poți testa apartenența la un set - pentru a verifica dacă un obiect are o proprietate cu un nume dat. Puteți efectua o astfel de verificare folosind operatorul în, folosind metode hasOwnProperty()Și propertyIsEnumerable() sau pur și simplu prin accesarea proprietății.

Operatorul in cere să i se dea un nume de proprietate (sub formă de șir) ca operand stânga și un obiect ca operand din dreapta. Returnează adevărat dacă obiectul are proprietatea proprie sau moștenită cu acest nume:

Var obj = ( x:1 ) "x" în obj; // adevărat: obj are propria sa proprietate „x” „y” în obj; // false: obj nu are proprietatea „y” „toString” în obj; // true: obj moștenește proprietatea toString

Metoda hasOwnProperty() a unui obiect verifică dacă obiectul are propria sa proprietate cu numele specificat. Pentru proprietățile moștenite, returnează false:

Var obj = ( x:1 ) obj.hasOwnProperty("x"); // true: obj are propria sa proprietate "x" obj.hasOwnProperty("y"); // false: obj nu are proprietatea "y" obj.hasOwnProperty("toString"); // false: toString - proprietate moștenită

Metoda propertyIsEnumerable() impune restricții suplimentare în comparație cu hasOwnProperty(). Returnează true numai dacă proprietatea specificată este o proprietate nativă al cărei atribut enumerabil este setat la true. Proprietățile obiectelor încorporate nu sunt enumerabile. Proprietățile create de un program JavaScript obișnuit sunt enumerabile, cu excepția cazului în care una dintre metodele ECMAScript 5 de mai jos a fost utilizată pentru a face proprietățile nenumerabile.

Adesea, în loc de operatorul in, este suficient să folosiți o expresie simplă de acces la proprietate și să utilizați operatorul !== pentru a verifica inegalitatea cu valoarea nedefinită:

Var obj = ( x:1 ) obj.x !== nedefinit; // adevărat: obj are proprietatea "x" obj.y !== nedefinit; // false: obj nu are proprietatea "y" obj.toString !== nedefinit; // true: obj moștenește proprietatea toString

Cu toate acestea, operatorul in distinge situațiile care nu se pot distinge folosind tehnica bazată pe proprietăți prezentată mai sus. Operatorul in distinge absența unei proprietăți de o proprietate care are valoarea nedefinită.

Enumerarea proprietăților

În loc să verificați proprietățile individuale, uneori doriți să iterați peste toate proprietățile existente sau să obțineți o listă cu toate proprietățile unui obiect. Acest lucru se face de obicei folosind o buclă for/in, dar standardul ECMAScript 5 oferă două alternative convenabile.

Instrucțiunea for/in loop execută corpul buclei pentru fiecare proprietate enumerabilă (fie proprie, fie moștenită) a obiectului specificat, atribuind numele proprietății unei variabile de buclă. Metodele încorporate moștenite de obiecte nu sunt enumerabile, iar proprietățile adăugate obiectelor de către programul dvs. sunt enumerabile (cu excepția cazului în care utilizați funcțiile descrise mai jos pentru a face proprietățile nenumerabile). De exemplu:

// Un obiect simplu cu trei proprietăți enumerabile var user = ( login:"kot86", nume:"Alexandr", vârsta:26); user.propertyIsEnumerable("toString"); // false, toString - metoda încorporată pentru (n în utilizator) console.log(n);

Unele biblioteci adaugă metode noi (sau alte proprietăți) obiectului Object.prototype, astfel încât acestea să poată fi moștenite și puse la dispoziție pentru toate obiectele. Cu toate acestea, până la standardul ECMAScript 5, nu a existat nicio modalitate de a face aceste metode suplimentare nenumerabile, așa că au ajuns să fie enumerate în bucle for/in. Pentru a rezolva această problemă, poate fi necesar să filtrați proprietățile returnate de bucla for/in. Mai jos sunt două exemple de implementare a unei astfel de filtre:

Pentru (n în utilizator) ( dacă (!user.hasOwnProperty(n)) continuă; console.log(n); ) pentru (n în utilizator) ( dacă (tip de utilizator[n] === „funcție”) continuă; console.log(n); )

În plus față de bucla for/in, standardul ECMAScript 5 definește două funcții care enumerează numele proprietăților. Primul dintre ei, Object.keys(), returnează o matrice de nume ale proprietăților enumerabile ale obiectului.

A doua funcție ECMAScript 5 care realizează enumerarea proprietăților este Object.getOwnPropertyNames(). Acționează ca funcția Object.keys(), dar returnează numele tuturor proprietăților proprii ale obiectului specificat, nu doar ale celor enumerabile. Implementările ECMAScript 3 nu au capacitatea de a implementa o astfel de funcționalitate deoarece ECMAScript 3 nu oferă capacitatea de a obține proprietăți nenumerabile ale unui obiect.

Metode de citire și scriere proprietăți

S-a spus deja mai sus că o proprietate de obiect are un nume, o valoare și un set de atribute. În ECMAScript 5, o valoare poate fi înlocuită cu una sau două metode, cunoscute sub numele de metode citește (getter)Și înregistrări (setter). Proprietățile pentru care sunt definite metode de citire și scriere sunt uneori numite proprietăți cu metode de acces pentru a le distinge de proprietățile datelor care reprezintă o valoare simplă.

Când un program încearcă să obțină valoarea unei proprietăți cu metode accesorii, interpretul apelează metoda read (fără argumente). Valoarea returnată de această metodă devine valoarea expresiei de acces la proprietate. Când un program încearcă să scrie o valoare într-o proprietate, interpretul apelează metoda write, pasând-i valoarea în dreapta operatorului de atribuire. Această metodă este responsabilă pentru „setarea” valorii proprietății. Valoarea returnată de metoda write este ignorată.

Spre deosebire de proprietățile datelor, proprietățile accesoriilor nu au un atribut care poate fi scris. Dacă o proprietate are atât metode de citire, cât și de scriere, este citire/scriere. Dacă o proprietate are doar o metodă de citire, este doar citire. Și dacă o proprietate are doar o metodă de scriere, este doar de scriere (acest lucru nu este posibil pentru proprietățile de date) și încercările de a citi valoarea unei astfel de proprietăți vor returna întotdeauna nedefinite.

Cel mai simplu mod de a defini o proprietate cu metode accesorii este de a folosi sintaxa de definiție literală a obiectului extins:

Var obj = ( // Proprietatea normală a datelor data_prop: valoare, // O proprietate cu metode de acces este definită ca o pereche de funcții get accessor_prop() ( /* corpul funcției */ ), set accessor_prop(valoare) ( ​​/* corpul funcției */ ) );

Proprietățile cu metode accesorii sunt definite ca una sau două funcții ale căror nume sunt aceleași cu numele proprietății și cu cuvântul cheie al funcției înlocuit cu get și/sau set.

Rețineți că nu vi se cere să utilizați două puncte pentru a separa numele proprietății de funcția care controlează accesul la proprietate, dar vi se cere totuși să utilizați o virgulă după corpul funcției pentru a separa metoda de alte metode sau proprietăți de date.

Ca exemplu, luați în considerare următorul obiect, care reprezintă coordonatele carteziene ale unui punct dintr-un plan. Are proprietățile obișnuite de date pentru a reprezenta coordonatele X și Y, precum și proprietăți cu metode accesorii pentru a obține coordonatele polare echivalente ale unui punct:

Var p = ( // x și y sunt proprietăți de date obișnuite, citire/scriere x: 1.0, y: 1.0, // r este o proprietate de citire/scriere cu două metode de acces. // Nu uitați să adăugați virgule după accesul metodelor get r() ( return Math.sqrt(this.x*this.x + this.y*this.y); ), set r(newvalue) ( ​​​​var oldvalue = Math.sqrt(this.x* this.x + this.y*this.y); var ratio = newvalue/oldvalue; this.x *= ratio; this.y *= ratio; ), // theta este o proprietate numai pentru citire cu singura metoda citește get theta() ( return Math.atan2(this.y, this.x); ) );

Rețineți utilizarea cuvântului cheie this în metodele de citire și scriere de mai sus. Interpretul va numi aceste funcții ca metode ale obiectului în care sunt definite, adică. în corpul funcției, aceasta se va referi la obiectul punct. Acest lucru permite metodei de citire a proprietății r să facă referire la proprietățile x și y, precum this.x and this.y.

Proprietățile cu metode accesorii sunt moștenite la fel ca proprietățile obișnuite ale datelor, astfel încât obiectul p definit mai sus poate fi folosit ca prototip pentru alte obiecte punct. Noile obiecte își pot defini propriile proprietăți x și y și vor moșteni proprietățile r și theta.

Atributele obiectului

Toate obiectele au atribute prototip, clasă și extensibile. Toate aceste atribute sunt descrise în subsecțiunile de mai jos.

atribut prototip

Atributul prototip al unui obiect specifică obiectul de la care sunt moștenite proprietățile. Este important să înțelegeți că atunci când codul programului Există o referință prototip, aceasta denotă o proprietate obișnuită a unui obiect, și nu atributul prototip.

Atributul prototip este setat atunci când obiectul este creat. Pentru obiectele create folosind literale, prototipul este Object.prototype. Prototipul unui obiect creat folosind operatorul new este valoarea proprietății prototip a constructorului. Iar prototipul obiectului creat folosind Object.create() este primul argument al acestei funcții (care poate fi nulă).

Standardul ECMAScript 5 oferă capacitatea de a defini prototipul oricărui obiect prin trecerea acestuia la o metodă Object.getPrototypeOf(). ECMAScript 3 nu are o funcție echivalentă, dar puteți defini adesea prototipul obj folosind expresia obj.constructor.prototype.

Obiectele create folosind operatorul nou moștenesc de obicei proprietatea constructor O referință la funcția de constructor folosită pentru a crea obiectul. Și așa cum am menționat mai sus, funcțiile de constructor au o proprietate prototip, care definește prototipul obiectelor create folosind acest constructor.

Rețineți că obiectele create folosind literalmente obiect sau Object.create() primesc o proprietate de constructor care se referă la constructorul Object(). Astfel, constructor.prototype se referă la adevăratul prototip pentru literalele obiect, dar de obicei nu este cazul obiectelor create prin apelarea Object.create().

Pentru a determina dacă un obiect este un prototip (sau o verigă dintr-un lanț de prototipuri) al altui obiect, utilizați metoda isPrototypeOf(). Pentru a afla dacă p este prototipul obj, trebuie să scrieți expresia p.isPrototypeOf(obj). De exemplu:

Var p = (x:1); // Definiți un obiect prototip. var obj = Object.create(p); // Creați un obiect cu acest prototip. p.isPrototypeOf(obj); // => adevărat: obj moștenește p Object.prototype.isPrototypeOf(p); // => adevărat: p moștenește Object.prototype

atribut de clasă

Atributul de clasă al unui obiect este un șir care conține informații despre tipul obiectului. Nici ECMAScript 3, nici ECMAScript 5 nu oferă posibilitatea de a schimba acest atribut și oferă doar modalități indirecte de a-i determina valoarea. În mod implicit, metoda toString() (moștenită de la Object.prototype) returnează un șir ca:

Prin urmare, pentru a determina clasa unui obiect, puteți încerca să apelați metoda toString() a acestui obiect și să extrageți subșirul de la al optulea până la penultimul caracter din rezultat. Partea dificilă este că multe metode moștenesc de la alte implementări mai utile ale toString(), iar pentru a apela versiunea corectă a toString() trebuie să efectuați un apel indirect folosind metoda Function.call().

Exemplul de mai jos definește o funcție care returnează clasa oricărui obiect care i-a fost transmis:

// Numele funcției clasei de obiect classof(obj) ( if (obj === null) return "Null"; if (obj === undefined) return "Undefined"; return Object.prototype.toString.call(obj) .slice (8,-1); )

Această funcție classof() poate primi orice valoare permisă în JavaScript. Numerele, șirurile de caractere și valorile booleene acționează ca obiecte atunci când toString() este apelat pe ele, dar valorile nule și nedefinite sunt tratate diferit.

atribut extensibil

Atributul extensibil al unui obiect determină dacă noi proprietăți pot fi adăugate obiectului. În ECMAScript 3, toate obiectele încorporate și definite de utilizator erau implicit extensibile, iar extensibilitatea obiectelor runtime era specifică implementării. În ECMAScript 5, toate obiectele încorporate și definite de utilizator sunt extensibile, cu excepția cazului în care au fost convertite în obiecte neextensibile, iar extensibilitatea obiectelor de execuție este încă specifică implementării.

Standardul ECMAScript 5 definește funcții pentru obținerea și modificarea atributului de extensibilitate al unui obiect. Pentru a determina dacă un obiect poate fi extins, trebuie să-l transmiteți metodei Object.isExtensible(). Pentru a face un obiect neextensibil, trebuie să-l transmiteți unei metode Object.preventExtensions(). Rețineți că, odată ce un obiect este făcut non-extensibil, nu poate fi făcut din nou extensibil. Rețineți, de asemenea, că apelul la preventExtensions() afectează doar extensibilitatea obiectului în sine. Dacă sunt adăugate noi proprietăți la prototipul unui obiect neextensibil, obiectul neextensibil va moșteni acele noi proprietăți.

Scopul atributului extensibil este de a face posibilă „repararea” obiectelor într-o anumită stare, interzicând modificările. Atributul extensibil al obiectelor este adesea folosit împreună cu atributele de proprietate configurabile și inscriptibile, astfel încât ECMAScript 5 definește funcții care facilitează setarea acestor atribute în același timp.

Metodă Object.seal() acționează ca metoda Object.preventExtensions(), dar nu numai că face obiectul neextensibil, ci face și toate proprietățile obiectului neconfigurabile. Adică, proprietăți noi nu pot fi adăugate la obiect și proprietățile existente nu pot fi șterse sau configurate. Cu toate acestea, proprietățile inscriptibile existente pot fi încă modificate.

Odată ce Object.seal() este apelat, obiectul nu poate fi returnat la starea anterioară. Pentru a determina dacă metoda Object.seal() a fost apelată pe un obiect, puteți apela metoda Object.isSealed().

Metodă Object.freeze() asigură o fixare și mai rigidă a obiectelor. Pe lângă faptul că face obiectul neextensibil și proprietățile sale neconfigurabile, face, de asemenea, toate proprietățile native ale datelor doar în citire. (Acest lucru nu se aplică proprietăților obiectului cu metode accesorii care au metode de scriere; acele metode vor fi în continuare apelate prin instrucțiuni de atribuire.) Pentru a determina dacă metoda Object.freeze() a obiectului a fost apelată, puteți apela Object.isFrozen().

Este important să înțelegeți că Object.seal() și Object.freeze() afectează doar obiectul care le este transmis: nu afectează prototipul acelui obiect. Dacă programul dvs. trebuie să comite complet un obiect, probabil că va trebui să capturați și obiectele din lanțul de prototipuri.

Serializarea obiectelor

Serializarea obiectelor este procesul de conversie a obiectelor într-o formă de reprezentare șir, care poate fi folosită ulterior pentru a le restaura. ECMAScript 5 oferă funcții încorporate pentru serializarea și restaurarea obiectelor JavaScript JSON.stringify()Și JSON.parse(). Aceste funcții folosesc formatul de schimb de date JSON. Numele JSON provine de la " Obiect JavaScript Notație" (o formă de notație pentru obiectele JavaScript), iar sintaxa acestei forme de notație amintește de sintaxa literalelor obiect și matrice în limbajul JavaScript:

Var obj = (x:1, y:(z:)); // Definiți un obiect de testare var s = JSON.stringify(obj); // s == "("x":1,"y":("z":))" var p = JSON.parse(s); // p - copie a obiectului obj

Sintaxa formatului JSON este doar un subset al sintaxei JavaScript și nu poate fi utilizată pentru a reprezenta toate valorile posibile permise în JavaScript. Suportat și poate fi serializat și restaurat: obiecte, matrice, șiruri de caractere, valori numerice finite, adevărat, fals și nul. Valorile NaN, Infinity și -Infinity sunt serializate la nul. Obiectele date sunt serializate în șiruri de date ISO, dar JSON.parse() le lasă în reprezentarea lor și nu restaurează obiectele originale Date.

Obiectele Function, RegExp și Error și valoarea nedefinită nu pot fi serializate sau restaurate. Funcția JSON.stringify() serializează numai proprietățile native enumerabile ale unui obiect. Dacă valoarea unei proprietăți nu poate fi serializată, proprietatea este pur și simplu exclusă din reprezentarea șirului. Atât JSON.stringify() cât și JSON.parse() au un al doilea argument opțional care poate fi utilizat pentru a personaliza procesul de serializare și/sau recuperare, de exemplu prin definirea unei liste de proprietăți care urmează să fie serializate sau a unei funcții pentru transformarea valorilor în timpul serializării.

depp 7 ianuarie 2009 la 23:56

Lucrul cu obiecte în JavaScript: teorie și practică

  • JavaScript

În acest articol, vreau să vorbesc cât mai complet și consecvent posibil despre ce este un obiect în JavaScript, care sunt capabilitățile acestuia, ce relații pot fi construite între obiecte și ce metode de moștenire „nativă” decurg din aceasta, cum afectează toate acestea. performanta si ce sa faci in general cu toate astea :)

Articolul NU va avea un cuvânt despre: emularea paradigmei tradiționale de clasă-obiect, zahăr sintactic, învelișuri și cadre.

Complexitatea materialului va crește de la începutul până la sfârșitul articolului, așa că pentru profesioniști primele părți pot părea plictisitoare și banale, dar apoi va fi mult mai interesant :)

Obiecte în JavaScript

Multe articole conțin expresia „În JavaScript, totul este un obiect”. Din punct de vedere tehnic, acest lucru nu este în întregime adevărat, dar face impresia potrivită începătorilor :)

Într-adevăr, mult în limbaj este un obiect și chiar și ceea ce nu este un obiect poate avea unele dintre capacitățile sale.

Este important să înțelegem că cuvântul „obiect” este folosit aici nu în sensul „un obiect al unei clase”. Un obiect în JavaScript este în primul rând doar o colecție de proprietăți (dacă preferați, îl puteți numi o matrice sau o listă asociativă) constând din perechi cheie-valoare. Mai mult, cheia poate fi doar un șir (chiar și pentru elemente de matrice), dar valoarea poate fi orice tip de date enumerate mai jos.

Deci, în JavaScript există 6 tipuri de bază datele sunt Nedefinite (indicând absența unei valori), Null, Boolean (Boolean), String (șir), Number (număr) și Object (obiect).
Mai mult, primele 5 sunt primitiv tipuri de date, dar Object nu este. În plus, putem considera convențional că tipul Object are „subtipuri”: matrice (Matrice), funcție (Funcție), expresie regulată (RegExp) și altele.
Aceasta este o descriere oarecum simplificată, dar în practică este de obicei suficientă.

În plus, tipurile primitive String, Number și Boolean sunt legate în anumite moduri de „subtipurile” neprimitive ale Object: String, Number și, respectiv, Boolean.
Aceasta înseamnă că șirul „Hello, world”, de exemplu, poate fi creat fie ca valoare primitivă, fie ca obiect String.
Pe scurt, acest lucru se face astfel încât programatorul să poată folosi metode și proprietăți atunci când lucrează cu valori primitive ca și cum ar fi obiecte. Puteți citi mai multe despre acest lucru în secțiunea corespunzătoare a acestui articol.

Lucrați de pe link

Un link este un mijloc de accesare a unui obiect sub nume diferite. Lucrul cu orice obiect se efectuează exclusiv prin referință.
Să demonstrăm acest lucru cu un exemplu:
test= funcția () (alertă ("Bună ziua!" )) //Creează o funcție (alertă ("Bună ziua!")) (și o funcție, după cum ne amintim, este un obiect cu drepturi depline) și face din variabila de test o referință la ea
test_link=test; //test_link se referă acum și la funcția noastră
Test(); //Buna ziua!
test_link(); //Buna ziua!


După cum putem vedea, atât prima legătură cât și a doua dau același rezultat.
Trebuie să realizăm că nu avem nicio funcție numită test și că variabila de test nu este un fel de legătură „principală” sau „primară”, iar „test_link” este una minoră.

Funcția noastră, ca orice alt obiect, este pur și simplu o zonă din memorie și toate referințele la această zonă sunt absolut echivalente. Mai mult decât atât, este posibil ca obiectul să nu aibă deloc referințe - în acest caz se numește anonim și poate fi folosit numai imediat după creare (de exemplu, trecut la o funcție), altfel va fi imposibil de accesat și va fi în curând fi distrus de garbage collector (colectare de gunoi), care este responsabil pentru ștergerea obiectelor fără referințe.

Să vedem de ce este atât de important să înțelegem asta:

test=(prop: "un text") //Creează un obiect cu proprietatea prop
test_link=test; //Creează un alt link către acest obiect

Alert(test.prop); //un text

//Modifică proprietatea obiectului
test_link.prop="newtext" ;

Alert(test.prop); //text nou
alert(test_link.prop); //text nou
/*S-ar putea spune că proprietatea s-a schimbat atât aici, cât și acolo - dar nu este așa.
Există un singur obiect. Deci proprietatea s-a schimbat o dată pe ea, iar linkurile continuă doar să indice acolo unde indică. */

//Adăugați o nouă proprietate și eliminați-o pe cea veche
test.new_prop="bună ziua" ;
şterge test.prop;

Alertă(test_link.prop); //undefined - această proprietate nu mai există
alert(test_link.new_prop);

//Ștergeți linkul
sterge testul;
alert(test.new_prop);
/*În acest moment, scriptul va arunca o eroare, deoarece testul nu mai există, iar test.new_prop nu există cu atât mai mult */
alert(test_link.new_prop); //Buna ziua
/* dar aici totul este în ordine, pentru că nu am șters obiectul în sine, ci doar un link către el. Acum obiectul nostru este indicat de un singur link, test_link */

//Creează un nou obiect
test=test_link; //Mai întâi, creați din nou legătura de testare
test_link=(prop: "un text" ) //Și aici este noul obiect

Alertă(test_link.prop); //un text
alert(test.prop); //nedefinit
/* Crearea unui nou obiect rupe legătura de referință, iar acum test și test_link indică diferite obiecte.
De fapt, acest lucru este echivalent cu ștergerea test_link-ului și crearea lui din nou, dar arătând către un obiect diferit */
alert(test.new_prop); //bună ziua - acum testul conține un link către primul nostru obiect


* Acest cod sursă a fost evidențiat cu Sursa de evidențiere a codului.

Acest comportament al obiectelor ridică adesea o mulțime de întrebări pentru dezvoltatorii începători, așa că sper că acest text va aduce puțină claritate. Dacă dorim să creăm o copie cu adevărat nouă, independentă a unui obiect, și nu o legătură, atunci singura modalitate de a face acest lucru este să creăm un nou obiect și să copiați acolo proprietățile necesare.

De asemenea, este de remarcat faptul că lucrul cu obiecte prin referință, pe lângă efectele distractive enumerate mai sus, oferă și economii semnificative de memorie, ceea ce este important atunci când un obiect este utilizat pe scară largă în diferite locuri din program.

Valori primitive

După cum am menționat mai sus, tipurile de date String și Number pot fi fie obiecte, fie valori primitive.
obj= new String(„bună ziua”); //Creează un șir ca obiect
simplu="bună ziua"; //Creează o valoare primitivă

Alerta(obj); //Buna ziua
alertă (simplu); //bună ziua - până acum totul este previzibil

Alerta(lungimea obiectului); //6 - un obiect de tip String are o proprietate length care stochează lungimea șirului
alert(simple.length); //6
/* Deși simplu nu este un obiect, putem accesa același set de proprietăți ca și un obiect de tip String. Este destul de convenabil */

Obj.prop="text" ;
simple.prop="text" ;

Alert(obj.prop); //text - deoarece obj este un obiect obișnuit, îi putem oferi cu ușurință o altă proprietate
alert(simple.prop); //nedefinit - dar simplu nu este un obiect, iar acest număr nu va funcționa pentru noi

* Acest cod sursă a fost evidențiat cu Sursa de evidențiere a codului.


Același lucru este valabil atât pentru tipurile Number, cât și pentru Boolean (ei bine, cu excepția faptului că nu au o proprietate de lungime, dar au o serie de alte proprietăți grozave).
Folosirea șirurilor și numerelor ca obiecte nu are niciun beneficiu practic, deoarece valorile primitive sunt mai convenabile de utilizat, dar păstrează în același timp toată funcționalitatea necesară. Cu toate acestea, pentru a completa imaginea, este necesar să înțelegem acest mecanism.

Nu confundați utilizarea valorilor primitive cu utilizarea literalelor - de exemplu, dacă creăm o matrice ca „test=new Array()” sau ca „test=", rezultatul va fi în continuare același obiect. Nu vom primi nicio valoare primitivă.

Crearea și utilizarea obiectelor

Deci, spre deosebire de limbajele care implementează paradigma clasă-obiect, nu trebuie să creăm mai întâi o clasă și apoi să creăm un obiect al clasei. Putem crea imediat un obiect, ceea ce vom face în următorul exemplu:
test=(
simple_property: „Bună ziua”,
proprietate_obiect: (
user_1: „Petya” ,
user_2: „Vasya”
},
function_property: function (utilizator) (
alert(acest .simple_property + ", " + this .object_property);
}
}

Test.function_property("user_1" ); //Bună, Petya.

* Acest cod sursă a fost evidențiat cu Sursa de evidențiere a codului.


Avem un obiect de testare care are 3 proprietăți, ale căror nume, sper, vorbesc de la sine. Ceea ce ne interesează cel mai mult este function_property, care conține funcția. O astfel de funcție poate fi numită o metodă obiect.

Funcția noastră folosește de două ori cuvântul cheie this, care este un pointer (adică, o referință) la obiectul de la care este apelată funcția. Astfel, this.simple_property=test.simple_property="Bună ziua", și this.object_property=test.object_property="Peter".

Este important să fie clar că acest lucru indică întotdeauna obiectul de la care este apelată funcția și nu obiectul căruia îi aparține. Deși în acest exemplu sunt același obiect, nu este întotdeauna cazul.

test.function_property("utilizator_1"); //Bună, Petya.

Test2=Obiect nou(); //O altă formă de a crea un obiect nou, similar cu test2=()

Test.function_property.call(test2, "user_1" ); //eroare
/* Metoda de apel vă permite să apelați o funcție în numele altui obiect. ÎN în acest caz,, numim metoda function_property a obiectului de testare, iar aceasta nu mai indică la obiectul de testare, ci la obiectul test2. Și pentru că nu are proprietatea object_property, atunci când încercați să obțineți this.object_property scriptul va arunca o eroare */

//să încercăm să remediam situația
test2.simple_property="O zi bună" ;
test2.object_property=test.object_property; //În acest caz, vom folosi specificarea obiectului prin referință pentru a nu duplica codul

Test.function_property.call(test2, "user_1" ); //Bună ziua, Petya.


* Acest cod sursă a fost evidențiat cu Sursa de evidențiere a codului.

De asemenea, ar trebui să fie clar din exemplu că nu există pași clari pentru crearea și utilizarea unui obiect. Un obiect poate fi modificat în orice mod în orice moment - înainte, după și chiar în timpul utilizării. Este prea diferenta importanta din OOP „tradițional”.

Constructor

În exemplul de mai sus, am creat 2 obiecte care au avut unele similarități. Ambele aveau proprietăți simple_property și object_property. Evident, atunci când scrieți cod real, apare adesea sarcina de a crea obiecte identice sau pur și simplu similare. Și, desigur, nu trebuie să creăm manual fiecare astfel de obiect.

Un designer ne va veni în ajutor. Un constructor în JavaScript nu face parte dintr-o clasă (pentru că nu există clase), ci pur și simplu o funcție în sine. Cea mai comună funcție.

make_me= functie (_nume) (
alert("Am fost lansat");
acest .nume=_nume;

}


/* Să ne dăm seama ce se întâmplă aici. Interpretul vede noul operator și verifică ce este în dreapta acestuia. Deoarece make_me este o funcție și poate fi folosită ca constructor, apoi un nou obiect este creat în memorie și funcția make_me este lansată pentru execuție, iar acest lucru indică exact acest nou obiect. Apoi, acest obiect este adăugat cu o proprietate name, căruia i se atribuie valoarea din argumentul _name și o metodă show_name. De asemenea (nu știu în ce moment, dar nu contează) variabila copil începe să indice către obiectul nostru nou-nouț, tocmai născut */

Alerta(nume.copil); //Vasya
child.show_name(); //Vasya


child2.show_name(); //Petru

Child2.show_name=funcție () (alertă( „Nu îmi voi spune numele”);} //Nu uitați că ne putem schimba obiectele în orice moment
child2.show_name(); //Nu îmi voi spune numele

Child.show_name(); //Vasya - copiii nu se influențează între ei în niciun fel


* Acest cod sursă a fost evidențiat cu Sursa de evidențiere a codului.

De asemenea, puteți compara un designer cu un tată - el dă naștere unui copil, înzestrându-l cu anumite calități, dar imediat după creare copilul devine complet independent de părinte și poate deveni foarte diferit de frații săi.
Dacă ne amintim descrierea tipurilor de date de la începutul articolului, devine clar că Object și subtipurile sale (Funcție, Matrice și altele) sunt de fapt constructori care conferă obiectului creat capabilitățile unei funcții, matrice etc.

Deci asta este deja mult mai bine. Acum avem capacitatea de a crea obiecte după un model. Totuși, încă nu este totul bine. În primul rând, fiecare obiect pe care îl creăm și toate proprietățile și metodele sale ocupă un loc separat în memorie, deși în multe feluri sunt repetate. În al doilea rând, dacă vrem să menținem legătura dintre părinte și copil și să putem schimba toate obiectele copil simultan. Un prototip ne va veni în ajutor.

Prototip

Așa cum fiecare copil are un tată și o mamă (cel puțin în sens biologic), la fel și fiecare obiect din JavaScript. Și dacă tatăl, așa cum am stabilit, lucrează ca designer, atunci mama este tocmai prototipul. Să vedem cum se întâmplă asta:
make_me= functie (_nume) (
alert("Am fost lansat");
acest .nume=_nume;
acest .show_name=funcție () (alertă (acest .nume);)
}
/*
Văzând cuvântul cheie al funcției, interpretul verifică codul din dreapta acestuia și așa mai departe. totul este ok - creează un nou obiect în memorie, care este și funcția noastră. Apoi, automat (fără intervenția programatorului) este creată o proprietate prototip pentru această funcție, care se referă la un obiect gol. Dacă am face acest lucru manual, ar arăta ca make_me.prototype=new Object();

Apoi, acestui obiect (indicat de proprietatea prototip) i se dă automat și o proprietate de constructor, indicând înapoi la funcție. Se pare că aceasta este o legătură ciclică.

Acum acest obiect, care poate fi descris ca (constructor: ... aici este o referință la o funcție...) este prototipul funcției.
*/

//Obiect - într-adevăr, un obiect
alert(typeof make_me.prototype.constructor); //Funcția este funcția noastră
alert(make_me.prototype.constructor === make_me); //Adevărat

//Adăugați o nouă metodă la prototipul funcției make_me

Copil=new make_me ("Vasya"); //Am fost lansat
/* Acum, pe lângă tot ceea ce este descris în exemplul anterior, o proprietate ascunsă suplimentară [] este creată în obiectul copil, care indică același obiect ca make_me.prototype. Deoarece Proprietatea este ascunsă, nu putem nici să-i vedem valoarea, nici să o schimbăm - cu toate acestea, joacă un rol important în lucrările ulterioare */

Alerta(nume.copil); //Vasya
child.show_name(); //Vasya

Child.set_name("Kolya");
/* În primul rând, interpretul caută metoda set_name în obiectul copil. Deoarece nu este acolo, continuă să caute în proprietatea child.[, o găsește acolo și o rulează. */
child.show_name(); //Kolya - acum numele lui Vasya este Kolya :)

Make_me.prototype.show_name2=funcție () (alertă ("Bună ziua, " + acest .nume;) //Deoarece un prototip este un obiect obișnuit, la fel de bine îl putem schimba din mers

Copil2=new make_me("Petya" );
copil2.show_name2(); //Bună, Petya
copil.show_name2(); //Bună, Kolya - modificările în prototip afectează nu numai obiectele nou create, ci și pe toate cele vechi

Child2.show_name2=funcție () (alertă( „Nu îmi voi spune numele”);} //Putem încă schimba obiectul în sine, în timp ce noua metodă show_name2 din acest obiect (și numai în el) este, parcă, „suprascrisă” metoda veche din prototip
copil2.show_name2(); //Nu îmi voi spune numele - pentru că... acum avem propria noastră metodă show_name2, apoi este numită, iar căutarea în prototip nu are loc

Child.show_name2(); //Bună ziua, Kolya - totul este la fel aici

Make_me.prototype=(prop: „bună ziua”) //Să încercăm să recreăm prototipul din nou

Alertă(copil.prop); //nedefinit
copil.show_name2(); //Bună Kolya
/* Dacă vă amintiți ce este lucrul prin referință, atunci totul este clar. Recrearea prototipului întrerupe conexiunea, iar acum proprietatea [] a obiectelor copil și child2 indică către un obiect (care era anterior prototipul funcției make_me), iar proprietatea make_me.prototype indică către un alt obiect, care este noul obiect. prototipul funcției make_me */

Child3=new make_me("Oleg" );
alert(copil3.prop); //bună ziua - așa cum era de așteptat


* Acest cod sursă a fost evidențiat cu Sursa de evidențiere a codului.

După cum se vede din exemplu, atâta timp cât tatăl rămâne fidel mamei (adică atât timp cât tipul de funcție rămâne același), toți copiii depind de mamă și sunt sensibili la toate schimbările din ea. Totuși, de îndată ce părinții divorțează (designerul schimbă prototipul cu altul), copiii fug imediat în toate direcțiile și nu mai există contact cu ei.

Un pic despre terminologie
Atâta timp cât legătura primară dintre proiectant și prototip nu este întreruptă, putem observa următoarea imagine:

make_me= functie (_nume) (
alert("Am fost lansat");
acest .nume=_nume;
acest .show_name=funcție () (alertă (acest .nume);)
}

Make_me.prototype.set_name=funcție (_name) (acest .name=_name;)
copil=new make_me("Vasya" );

Alertă (tip de make_me.prototype); //obiect - funcția are o proprietate prototip
alert(tip de copil.prototip); //nedefinit - obiectul creat NU are o proprietate prototip
alert(child.constructor.prototype === make_me.prototype); //true - dar obiectul are o proprietate de constructor, care indică funcția de constructor make_me, care, la rândul său, are o proprietate de prototip


* Acest cod sursă a fost evidențiat cu Sursa de evidențiere a codului.

După cum am observat după ce am citit numeroase forumuri pe acest subiect, principala problemă pe care o au oamenii este atunci când confundă proprietatea prototip a unei funcții cu proprietatea ascunsă [] a obiectului creat de acea funcție.
Ambele proprietăți sunt o referință la același obiect (atâta timp cât conexiunea primară dintre prototip și constructor nu este întreruptă), dar sunt totuși proprietăți diferite, cu nume diferite, dintre care unul este accesibil programatorului și celălalt nu este.

Este întotdeauna necesar să înțelegem clar că, dacă vorbim despre prototipul constructorului, atunci aceasta este întotdeauna proprietatea prototipului, iar dacă vorbim despre prototipul obiectului creat, atunci aceasta este proprietatea ascunsă [].

Moştenire

Acum știm că fiecare obiect are o referință de prototip ascunsă și fiecare prototip este un obiect obișnuit.
Cei mai sensibili cititori au prins deja mirosul recursiunii :)
Într-adevăr, pentru că un prototip este un obiect obișnuit, apoi el, la rândul său, are o legătură cu prototipul său și așa mai departe. În acest fel, se implementează o ierarhie de prototipuri.
pasăre= funcţie()() //Acesta este constructorul păsării
bird.prototype.cry=funcție ()(alertă(„Plânge!”);) //Pasarea poate striga
bird.prototype.fly=funcție ()(alertă(„zboară!”);) //și zboară

Duck=funcție () ()
duck.prototype=pasare noua();
duck.prototype.cry=funcție ()(alertă(„Cărlatan!” ;) //Rața țipă altfel
duck.prototype.constructor=rata; //Setați forțat proprietatea prototype.constructor la rață, deoarece altfel se va referi la pasăre

Billy = rata noua(); //Billy este rata noastră
billy.fly(); //Eu zbor! - Billy poate zbura pentru că este o pasăre.
billy.cry(); //Cărlatan, şarlatan! - Billy țipă șarlatan pentru că e o rață.


* Acest cod sursă a fost evidențiat cu Sursa de evidențiere a codului.

În acest fel, puteți implementa o ierarhie a oricărui nivel de imbricare.

Sarcina vedetă

Acum, din moment ce știm atât de multe despre toate acestea, să încercăm să ne dăm seama cât de multe se întâmplă în aceste trei rânduri
make_me= funcţie()()
copil=nou make_me();
alert(child.toString()); //ieșiri

* Acest cod sursă a fost evidențiat cu Sursa de evidențiere a codului.

Pe prima linie creăm o nouă funcție și o variabilă numită make_me care indică acea funcție. Aceasta creează un prototip de funcție, make_me.prototype, care conține o proprietate de constructor care indică către make_me.
Dar asta nu este tot:)
Deoarece funcția make_me este, de asemenea, un obiect, apoi are, la rândul său, un tată și o mamă, i.e. designer și prototip. Constructorul său este o funcție nativă a limbajului Function(), iar prototipul său este un obiect care conține metodele call, apply etc. - Datorită acestui prototip putem folosi aceste metode în orice funcție. Astfel, funcția make_me are o proprietate [] care indică Function.prototype.

La rândul său, prototipul unui constructor Function este, de asemenea, un obiect, al cărui constructor este (surpriză!) Object (adică Function.prototype.[].constructor===Object), iar prototipul este un obiect care conține proprietățile standard. și metodele obiectului.cum ar fi toString, hasOwnProperty și altele (cu alte cuvinte - Function.prototype.[]["hasOwnProperty"] - aceasta este exact metoda pe care o putem folosi în toate obiectele derivate - și aceasta este metoda proprie a acestui obiect, și nu unul moștenit). În acest mod interesant descoperim că tot felul de obiecte sunt derivate din Object.

Putem continua mai departe? Se dovedește că nu. Object.prototype conține proprietățile de bază ale obiectului tocmai pentru că nu are propriul prototip. Object.prototype.[]=null; În acest moment, călătoria prin lanțul de prototipuri în căutarea unei proprietăți sau a unei metode se oprește.

O alta fapt interesant- constructorul Object este Function. Acestea. Object.[].constructor===Funcție.
Există o altă referință circulară - constructorul Object este Function, iar constructorul Function.prototype este Object.

Să revenim la exemplul nostru. Am înțeles deja cum este creată funcția, acum să trecem la a doua linie. Acolo creăm un obiect copil al cărui constructor este funcția make_me și al cărui prototip este make_me.prototype.

Ei bine, în a treia linie vedem cum interpretul urcă în lanț, de la copil la copil.[] (aka make_me.prototype), apoi la copil.[].[] (aka Object.prototype), și găsește deja acolo metoda toString, care lansează execuția.

Impurităţi

Poate părea că moștenirea prin prototipuri este singura modalitate posibilă în JavaScript. Este gresit.
Avem de-a face cu un limbaj foarte flexibil care oferă mai degrabă posibilități decât reguli.

De exemplu, dacă dorim, nu putem folosi prototipuri deloc, ci programăm folosind conceptul de mixin. Pentru asta vom avea nevoie de vechii noștri prieteni buni - designeri.

//Acesta este un constructor uman
om=funcție() (
this .live=function ()(alerta ("Sunt live" ;) //Omul știe să trăiască
acest .walk=funcție ()(alertă(„Mă plimb” ;) //Omul poate merge
}

//Acesta este constructorul poetului
poet=funcție ()(
aceasta .kill=funcție ()(alertă( „Poetul a ucis un om”);} //Un poet poate ucide o persoană
acest .live=funcție ()(alertă(„Sunt mort” ;) //O persoană va muri din asta
}

Vladimir=om nou(); //Vladimir este bărbat
vladimir.live(); // Eu trăiesc - el este în viață
vladimir.walk(); //I'm walking - el merge

Poet.call(vladimir); //Execută poetul constructor pentru obiectul vladimir
vladimir.kill(); //Poetul a ucis un om
vladimir.live(); //Sunt mort

//Acum concentrează-te
man.call(vladimir);
vladimir.live(); //Eu traiesc


* Acest cod sursă a fost evidențiat cu Sursa de evidențiere a codului.

Ce vedem în acest exemplu? În primul rând, este posibil să se moștenească de la mai multe obiecte care nu se află în aceeași ierarhie. În exemplu sunt 2, dar pot fi câte doriți.
În al doilea rând, nu există deloc ierarhie. Suprascrierea proprietăților și metodelor este determinată numai de ordinea în care sunt apelați constructorii.
În al treilea rând, aceasta este capacitatea de a schimba obiectul și mai dinamic și mai precis obiect separat, și nu toți copiii, ca la schimbarea prototipului.

Actualizare: Închideri și proprietăți private

Pentru a nu umfla acest articol deja destul de mare, ofer un link către o postare în care este scris despre asta în detaliu.

Ce să faci acum cu toate astea

După cum am spus mai sus, modificarea arbitrară a obiectelor individuale, utilizarea constructorilor, mixin-urilor și flexibilitatea prototipurilor sunt doar instrumente, oportunități care permit programatorului să creeze atât cod groaznic, cât și minunat în toate privințele. Este important doar să înțelegem ce probleme rezolvăm, prin ce mijloace, ce obiective atingem și ce preț plătim pentru asta.

Mai mult decât atât, problema prețului este destul de nebanală, mai ales dacă vorbim de dezvoltare sub motor de cautare Versiunile Explorer 6 și 7.
1. Memorie - totul este simplu aici. În toate browserele, moștenirea pe prototipuri ocupă mult mai puțină memorie decât atunci când se creează metode prin constructori. Mai mult, cu cât avem mai multe metode și proprietăți, cu atât mai multa diferenta. Cu toate acestea, merită să ne amintim că, dacă nu avem o mie de obiecte identice, ci doar unul, atunci consumul de memorie va fi în orice caz mic, deoarece Există și alți factori de luat în considerare aici.
2. Timpul procesorului – aici principalele subtilități sunt legate în mod specific de browserele de la Microsoft.
Pe de o parte, obiectele în care metodele și proprietățile sunt create printr-un constructor pot fi create de multe ori (în unele cazuri de zeci și sute de ori) mai încet decât printr-un prototip. Cu cât sunt mai multe metode, cu atât este mai lent. Deci, dacă IE-ul tău se blochează pentru câteva secunde în timpul inițializării scriptului, există un motiv pentru a săpa în această direcție.

Pe de altă parte, metodele proprii ale unui obiect (cele create prin constructor) se pot executa puțin mai rapid decât metodele prototip. Dacă aveți nevoie disperată de a accelera execuția unei anumite metode în acest browser, atunci trebuie să țineți cont de acest lucru. Rețineți că apelul metodei (adică căutarea acestuia în obiect) este accelerat, nu execuția sa. Deci, dacă metoda în sine rulează pentru o secundă, atunci nu veți observa o creștere mare a performanței.

În alte browsere probleme similare Se observă că timpul pentru crearea obiectelor și apelarea metodelor acestora este aproximativ același pentru ambele abordări.

P.S. De obicei, în articole de acest fel, autorul oferă un fel de înveliș, fie încercând să implementeze moștenirea de clasă-obiect bazată pe moștenirea prototipică, fie pur și simplu zahăr sintactic pentru moștenirea prototipică. Nu fac asta în mod intenționat, pentru că... Cred că o persoană care înțelege semnificația acestui articol este capabilă să scrie orice pachet pentru sine și multe alte lucruri interesante :)

Etichete:

  • OOP
  • moştenire
  • javascript
Adaugă etichete