Si të konfiguroni telefonat inteligjentë dhe PC. Portali informativ

Puna me objekte në JavaScript: teori dhe praktikë. Objektet JavaScript në Shembuj

Përshëndetje për të gjithë ata që e lexojnë këtë botim. Sot dua t'ju tregoj një mjet kyç të gjuhës - objektet JavaScript. Më lejoni t'ju kujtoj se js është ndër-shfletues dhe funksionon në të gjitha sistemet operative (windows, mac os, etj.). Ndryshe nga gjuhët e programimit të orientuara nga objekti, zbatimi i objekteve në js ndryshon ndjeshëm nga funksionaliteti i zakonshëm dhe variacionet në përdorimin e instancave, për shembull, në C#.

Prandaj, pasi të keni lexuar artikullin aktual, do të mësoni tiparet kryesore dalluese të objekteve të skriptit, do të mësoni se në çfarë mënyrash ato mund të krijohen, përditësohen dhe fshihen. Do të prek gjithashtu temën e vetive, metodave dhe konstruktorëve, do të flas për komanda të dobishme dhe, natyrisht, pak për trashëgiminë. Unë mendoj se është koha për të filluar mësimin!

Çfarë është një objekt në JavaScript dhe çfarë aftësish ka?

Në js, objektet janë vargje të thjeshta shoqëruese (ato quhen gjithashtu hash).

Çfarë është një grup shoqërues?

Kjo është një strukturë e të dhënave që ruan një sasi të caktuar informacioni që lidhet dhe përshkruan një element specifik. Të gjitha të dhënat janë të strukturuara dhe të ndërlidhura si "çelës => vlerë".

Për shembull, duhet të përshkruani makinat. Pastaj krijoni një objekt automatik dhe përshkruani karakteristikat e tij në një grup. Vendosa të përshkruaj markën e makinës (emrin), ngjyrën (ngjyrën) dhe koston (çmimin) e saj. Më poshtë kam bashkangjitur kodin për zbatimin e detyrës së përshkruar.

1 2 3 4 5 var avto = ( emri: "BMW 116i", ngjyra: "e zezë", çmimi: 588000 );

var avto = ( emri: "BMW 116i", ngjyra: "e zezë", çmimi: 588000 );

Këtu shihni një mënyrë për të krijuar një objekt të quajtur "avto". Emri, ngjyra dhe çmimi janë çelësat që mund të përdoren gjatë shkrimit të aplikacionit.

Unë e kalova veten me këtë shembull, kështu që tani le të shohim gjithçka në rregull.

Ju mund të krijoni një objekt në disa mënyra:

var auto = (); ose var auto = objekt i ri();

Në të dyja rastet, krijohet një objekt bosh me një emër të njohur, por opsioni i parë përdoret shumë më shpesh, pasi është më i shkurtër dhe më i përshtatshëm për t'u shkruar.

Gjithçka rreth pronave

Tani ju duhet të mbushni objektin bosh me parametra. Për ta bërë këtë, ju duhet të shtoni vetitë, të cilat unë i quajta gjithashtu çelësat më lart. Përsëri, ka dy mënyra për të deklaruar pronat.

Dua të vërej se JavaScript nuk ka një kornizë strikte për krijimin dhe inicializimin e parametrave të tillë. Karakteristikat e reja mund të shfaqen në të gjithë kodin, ashtu siç mund të fshihen dhe përditësohen.

Kështu, ju mund t'i krijoni të gjithë çelësat menjëherë ose t'i deklaroni kur të bëhen të disponueshëm. Dhe edhe nëse, gjatë shkrimit të një programi, i referoheni çelësave që nuk ekzistojnë, nuk do të ketë asnjë gabim. Në këtë rast, "i papërcaktuar" do të kthehet.

Mënyra e parë.

Krijimi dhe qasja në prona duke përdorur një pikë. Për të zbatuar këtë opsion, duhet të shkruani emrin e objektit, dhe më pas t'i shtoni emrin e çelësit përmes një pike dhe më pas të caktoni një vlerë përmes shenjës së barabartë:

avto.name = "BMW 116i"

Por në këtë metodë ju do të shtoni një element më shumë në çelësat ekzistues:

Kjo metodë përdoret kur emri i pronës tashmë dihet dhe duhet të bëni veprime të caktuara me vlerat.

Mënyra e dytë.

Nuk ndryshon nga e para, nëse krahasoni qëllimet e tyre. Sidoqoftë, kjo metodë ka një avantazh të vogël. Për këtë opsion, përdoren kllapa katrore:

avto[“emri”] = “BMW 116i”

Një shtesë e bukur është aftësia për të krijuar emra pronash në formën e çdo vargu. P.sh.

avto[“emri i makinës”] = “BMW 116i”

Puna me çelësa përmes kllapave katrore përdoret kur disa parametra futen nga përdoruesi dhe ruhen në variabla ose kur emrat e vetive janë të panjohura paraprakisht. Për shembull, një përdorues kërkon çmimin e një makine të zgjedhur. Elementi që u thirr shkruhet në variabël dhe çmimi dërgohet si përgjigje:

var auto = (); avto.name = "BMW_116i"; avto.çmimi = 588000; var tasti = "çmimi"; // çmimi i makinës u kërkua alarm(avto);

Tani le të kalojmë te fshirja e pronave. Gjithçka është shumë e thjeshtë këtu. Për të hequr, përdorni komandën fshij. Pra, nëse shtoni 2 rreshtat e mëposhtëm në shembullin e fundit më poshtë:

fshij auto.çmimin;

alarm (auto);

Më pas, kur telefononi alarmin për herë të dytë, kutia e dialogut do të shfaqë "të papërcaktuar".

Disa fjalë për kompaktësinë

Në fazën aktuale, ju thashë se si të krijoni një objekt dhe të përshkruani vetitë e tij. Kësaj i kam bashkangjitur rastet e provës, por më të vëmendshmit nga ju, të dashur lexues, keni vënë re se kodi i parë i programit është disi i ndryshëm nga të gjithë të tjerët.

Dhe gjithçka sepse përdor një paraqitje kompakte të të dhënave. Kjo është një metodë shumë e popullarizuar e deklarimit të çelësave, sepse është më e shkurtër për t'u shkruar dhe më e lehtë për t'u kuptuar vizualisht.

Le të kalojmë nëpër pronat tona

Në JavaScript, ju mund të përsërisni shpejt përmes vetive të krijuara. Për këtë qëllim, u sigurua një mekanizëm i veçantë, i njohur më mirë si ciklit.

Nëse jeni të njohur me gjuhë të tjera programimi, ju e dini se më shpesh unazat krijohen duke përdorur fjalën për, atëherë shkruhet në kllapa kushti për numërimin e elementeve.

Në js ngjan me një lak në pamjen e tij per secilin nga gjuha C#. Shikoni dizajnin e përgjithshëm:

për (var obj në objekt) ( // kryerja e kërkimit)

ku obj është përgjegjës për emrin e çelësave të numëruar,

objekt – për vlerat e tyre.

Dhe tani këtu është një shembull konkret për ju.

1 2 3 4 5 6 7 8 var avto = ( emri: "BMW 116i", ngjyra: "e zezë", çmimi: 588000 ); për (var obj në objekt) ( alarm(obj + ":" + objekt) )

var avto = ( emri: "BMW 116i", ngjyra: "e zezë", çmimi: 588000 ); për (var obj në objekt) ( alarm(obj + ":" + objekt) )

Është koha të njiheni me metodat

Gjuha e skriptimit parashikon krijimin e metodave. Ky është një mekanizëm absolutisht i thjeshtë me të cilin në çdo kohë mund të shtoni një metodë ose metoda në çdo objekt që zgjeron aftësitë e grupeve të krijuara shoqëruese. Ato quhen edhe vetitë e funksionit.

Vetë Js është shumë dinamike dhe mahnitëse deri diku. Kështu mund të krijoni elementë të llojeve të ndryshme. Kur mësoni këtë gjuhë, nuk keni nevojë të mësoni përmendësh struktura komplekse, pasi shumë deklarata janë shumë të ngjashme me njëra-tjetrën.

Pra, për të krijuar një metodë, duhet të deklaroni një objekt dhe më pas të filloni të shkruani një komandë që është tamam si krijimi i vetive. Megjithatë, pas “=” nuk shkruhet më vlera, por funksioni i fjalës kyçe (ndryshore). Dhe më pas veprimet renditen në kllapa kaçurrelë.

Këtu është zbatimi i këtij mekanizmi:

var avto =() avto.emri = “BMV” avto.viti = 1999 avto.drive = funksion(k) ( alarm(“Makina ka kaluar”+n+“ km.”)) avto.drive(300) avto. makinë (450)

Siç mund ta shihni, ky shembull përmban veti dhe metoda, thirrjet e të cilave fillimisht janë identike.

A ka JS gjithashtu konstruktorë?

Po zoteri! Në këtë gjuhë, gjithçka që përdor fjalën kyçe " i ri", automatikisht bëhet konstruktor. Pra, më lart patë deklaratën e një objekti bosh në formën: avto = objekt i ri ();. Ky është konstruktori.

Për qartësi, merrni parasysh linjat e mëposhtme.

var bob = objekt i ri();

bob.emri = "Bob Smith";

Megjithatë, ky nuk është i gjithë arsenali i mundësive. Në js, ju mund të krijoni konstruktorët tuaj dhe më pas t'i përdorni për të deklaruar objekte të reja.

Pra, unë dua të "bëj" një konstruktor me porosi për makinat tashmë ekzistuese. Ju lutemi vini re se emri duhet të jetë me shkronjë të madhe. Kjo është shenja dalluese e funksioneve. Për ta bërë këtë, unë shkruaj zbatimin e softuerit të mëposhtëm:

funksioni Auto (emri, çmimi) (

ky.emër = emër;

ky.çmimi = çmimi;

Tani, kur krijoni një numër të pakufizuar objektesh dhe aplikoni këtë konstruktor në to, të gjithë do t'i përkasin të njëjtës klasë. Për shembull:

var car1 = Avto i ri ("BMW", 650000);

var car2 = Avto i ri ("Audi", 520000);

Përveç kësaj, ju mund të krijoni metoda brenda konstruktorit.

Karakteristikat e trashëgimisë në JavaScript

Në mënyrë tipike, në shumë gjuhë, trashëgimia bazohet në klasa që mund të trashëgojnë nga njëra-tjetra. Pastaj mund të dëgjoni shprehje të tilla si "klasa e paraardhësve", "klasa e fëmijëve", etj.

Sidoqoftë, në js gjithçka është ndryshe. Këtu trashëgohen objektet.

E gjithë trashëgimia bazohet në një referencë të brendshme midis objekteve, e cila njihet si "prototip". Nëse shtoni ".prototype" në një metodë duke përdorur një pikë dhe më pas shkruani emrin e prototipit, atëherë të gjitha objektet e metodës së zgjedhur do të trashëgohen nga ky prototip.

Le të kalojmë në një shembull.

funksioni Transport (emri) ( this.name = emri this.canDrive = true ) var transport = transport i ri ("avto") // krijoi një objekt transporti funksion Bike (emri) ( this.name = emri ) Bike.prototype = transport / / specifikoni që të gjitha objektet e reja të kësaj klase do të përdorin transportin biçikletë1 = Biçikletë e re ("për_sport") bike2 = Biçikletë e re ("për_fëmijë") console.log(bike1.name) console.log(bike2.name) konsol .log (bike1.canDrive)

Unë mendoj se do të përfundoj këtu. Unë ju kam thënë për aspektet themelore të një gjuhe shkrimi. Megjithatë, kjo është vetëm njohuri sipërfaqësore. Më tej do të shkojmë më thellë. Ndërkohë, mos harroni të bashkoheni në radhët e pajtimtarëve të mi dhe të ndani lidhjen e artikullit me miqtë tuaj. Paç fat!

Mirupafshim!

Përshëndetje, Roman Chueshov

Lexoni: 97 herë

Objektet janë gurthemeli i JavaScript. Shumë lloje të dhënash të integruara përfaqësohen si objekte. Për të qenë një zhvillues i suksesshëm JavaScript, duhet të keni një kuptim të qartë se si funksionojnë ato. Blloqet e ndërtimit të një objekti quhen fushat e tij ose vetitë e objektit JavaScript. Ato përdoren për të përshkruar çdo aspekt të një objekti. Prona mund të përshkruajë gjatësinë e një liste, ngjyrën e qiellit ose datën e lindjes së një personi. Krijimi i objekteve është një proces i lehtë. Gjuha ofron një sintaksë të njohur si literale objektesh, të cilat shënohen me kllapa kaçurrelë.

Hyrja në Vetitë

Gjuha ofron dy hyrje për të hyrë në pronat. E para dhe më e zakonshme njihet si shënimi me pika. Në shënimin me pika, një burim mund të aksesohet duke specifikuar emrin e objektit pritës, i ndjekur nga pika dhe emri i pronës. Për shembull, kur objekti.foo fillimisht u vendos në një, atëherë vlera e tij do të bëhet 2 pasi të ekzekutohet deklarata e objekteve JavaScript.

Një sintaksë alternative e aksesit njihet si shënimi i kllapave. Në shënim, emri i objektit pasohet nga një grup kllapash katrore. Në to, emri i pronës specifikohet si varg:

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

Është më shprehës sesa shënimi me pikë sepse lejon një variabël të specifikojë të gjithë ose një pjesë të emrit të një prone. Kjo është e mundur sepse interpretuesi i objektit JavaScript e konverton automatikisht këtë shprehje në një varg dhe më pas merr vetinë përkatëse. Emrat e pronave krijohen menjëherë duke lidhur përmbajtjen e ndryshores f me vargun "oo":

objekt = "bar".

Shënimi i kllapave lejon që emrat e pronave të përmbajnë karaktere që janë të ndaluara në shënimin me pika. Për shembull, deklarata e mëposhtme është plotësisht e ligjshme në kllapa. Sidoqoftë, nëse përdoruesi përpiqet të krijojë të njëjtin emër të pronës në shënimin me pika, ai do të hasë një gabim sintaksor:

objekt["!@#$% &*()."] = e vërtetë.

Vetitë e objekteve të ndërlidhura JavaScript mund të aksesohen duke lidhur pika dhe/ose kllapa. Për shembull, objekti i mëposhtëm përmban një objekt të mbivendosur të quajtur baz që përmban një objekt tjetër të quajtur foo që ka një veti të quajtur bar që përmban vlerën pesë:

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

Shprehjet e mëposhtme aksesojnë pronën e bashkangjitur në shirit. Shprehja e parë përdor shënimin me pika, ndërsa shprehja e dytë përdor shënimin katror. Shprehja e tretë kombinon të dy hyrjet për të arritur të njëjtin rezultat:

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

Shprehjet si ato të paraqitura në shembullin e mëparshëm mund të shkaktojnë degradim të performancës nëse përdoren gabimisht dhe të shkaktojnë dështimin e objektit JavaScript. Vlerësimi i secilës shprehje pikë ose kllapa kërkon kohë. Nëse e njëjta veti përdoret shumë herë, atëherë ka kuptim të aksesoni një herë në pronë dhe më pas të ruani vlerën në një ndryshore lokale për të gjitha përdorimet e ardhshme.

Funksiononi si metodë

Kur një funksion përdoret si veti e një objekti, ai quhet metodë. Ashtu si vetitë, ato janë të specifikuara në shënimin literal të objektit. Për shembull:

var objekt = ( shuma: funksioni (foo, bar) (kthimi foo + bar; ) ).

Metodat e objektit JavaScript mund të thirren duke përdorur shenja dhe kllapa. Shembulli i mëposhtëm thërret metodën sum() nga shembulli i mëparshëm duke përdorur të dy hyrjet:

  • objekt.shuma(1, 2);
  • objekt["shuma"](1, 2).

Shënimi i fjalëpërfjalshëm i objektit është i dobishëm për krijimin e objekteve të reja, por nuk mund të shtojë veti ose metoda atyre ekzistuese. Për fat të mirë, shtimi i të dhënave të reja është po aq i lehtë sa krijimi i një deklarate caktimi. Krijohet një objekt bosh. Më pas, duke përdorur operatorët e caktimit, shtojmë dy veti, foo dhe bar, dhe metodën baz:

  • var objekt = ();
  • objekt.foo = 1;
  • objekt.bar = null;
  • objekt.baz = funksion() ( kthen "përshëndetje nga baz()"; ).

Enkapsulimi i programit

Ideja themelore e programimit të orientuar nga objekti është të ndajë programet në pjesë më të vogla dhe të bëjë çdo pjesë përgjegjëse për menaxhimin e gjendjes së vet. Kështu, disa njohuri se si funksionon një pjesë e një programi mund të jenë lokale për atë pjesë. Dikush që punon në pjesën tjetër të programit nuk duhet ta mbajë mend dhe as të dijë për të. Sa herë që këto të dhëna lokale ndryshojnë, vetëm kodi menjëherë përreth tij duhet të përditësohet.

Pjesët e ndryshme të një programi të tillë komunikojnë me njëra-tjetrën përmes ndërfaqeve, grupeve të kufizuara të funksioneve ose lidhjeve që ofrojnë funksionalitet të dobishëm në një nivel më abstrakt duke fshehur zbatimin e tyre të saktë. Pjesë të tilla të një programi modelohen duke përdorur objekte. Ndërfaqja e tyre përbëhet nga një grup specifik metodash dhe vetive. Vetitë që janë pjesë e një ndërfaqeje quhen publike. Pjesa tjetër, e cila nuk duhet të prekë kodin e jashtëm, quhet private.

Shumë gjuhë ofrojnë aftësinë për të bërë dallimin midis pronave publike dhe private dhe nuk lejojnë që kodi i jashtëm të hyjë në ato private. JavaScript, përsëri duke marrë një qasje minimaliste, nuk është ende aty. Aktualisht po punohet për të shtuar këtë gjuhë. Prandaj, programuesit JavaScript do ta përdorin me sukses këtë ide. Në mënyrë tipike, ndërfaqja e disponueshme përshkruhet në dokumentacion ose komente. Është gjithashtu praktikë e zakonshme të vendoset një nënvizim (_) në fillim të emrave të pronave për të treguar se ato prona janë private. Ndarja e ndërfaqes nga zbatimi është një ide e shkëlqyer. Kjo zakonisht quhet kapsulim.

Vetitë

Një objekt me kllapa (...) quhet objekt literal. Ju mund të vendosni menjëherë disa prona në kllapa të tilla (...). Për shembull, çiftet "çelës: vlera dhe kështu me radhë":

le përdoruesi = ( // emri i një objekti: "John", // nga çelësi "name" ruaj vlerën "John" age: 30 // by key "age" store value 30 }.!}

Një pronë ka një çelës (i njohur gjithashtu si "emër" ose "identifikues") përpara një dy pika ":" dhe një vlerë në të djathtë të tij. Objekti i përdoruesit ka dy veti. Objekti i përdoruesit JavaScript që rezulton me dy skedarë të nënshkruar të emërtuar "emri" dhe "mosha". Mund të shtoni, fshini dhe lexoni skedarë prej tij në çdo kohë. Vlerat e vetive arrihen duke përdorur shënimin e pikave. Mund të jetë i çdo lloji. Mund të shtoni një vlerë boolean. Për të hequr një pronë, përdorni delete në rastin e gabimit të një objekti JavaScript.

Të gjitha objektet e gabimit JavaScript janë pasardhës të objektit Error ose një objekti të trashëguar:

  1. Objekti i Gabim sintaksor trashëgon nga objekti Error.
  2. JSON gabim analizimi i një lloji të caktuar të objektit të gabimit sintaksor.

Për të marrë një zhytje edhe më të thellë në të kuptuarit se si aplikacionet merren me gabimet e JavaScript, hidhini një vështrim më të afërt Airbrake JavaScript, një mjet gjurmimi i gabimeve për sinjalizimet në kohë reale dhe një pasqyrë e menjëhershme për atë që shkoi keq me kodin tuaj JavaScript.

Mesazhet e gabimit që një përdorues mund të marrë përpara se të fshijë një objekt JavaScript:

  1. Karakter i keq i kontrollit në një varg fjalë për fjalë.
  2. Karakteri i keq në një varg fjalë për fjalë.
  3. Dalje e dobët e Unicode.
  4. Karakteri i keq i arratisjes.
  5. Varg i pandërprerë.
  6. Kod jo-numerik i papritur.
  7. Nuk ka numra pas presjes dhjetore.
  8. Numri thyesor i pandërprerë.
  9. Nuk ka numra pas treguesit të shkallës.
  10. Nuk ka numra pas shenjës së eksponentit.
  11. Pjesa eksponenciale nuk ka numër.
  12. Fund i papritur i të dhënave.
  13. Fjalë kyçe e papritur.
  14. Një simbol i papritur.
  15. Fundi i të dhënave gjatë leximit të përmbajtjes së një objekti.
  16. Emri i pritshëm i pronës ose ")".

Vetitë llogaritëse

Ju mund të përdorni kllapa katrore në një objekt fjalë për fjalë. Këto quhen veti të llogaritura. Një shembull është dhënë më poshtë.

Kuptimi i një vetie të llogaritur është i thjeshtë: do të thotë që emri i pronës duhet të merret nga fruta. Pra, nëse një vizitor hyn në "mollë", çanta do të bëhet (mollë: 5). Mund të përdorni shprehje më komplekse në kllapa katrore:

le fruta = "mollë";

: 5 // thes.appleKompjuterë = 5

Kllapat katrore janë shumë më të fuqishme se shënimi me pika. Ato lejojnë emrat e pronave dhe variablave. Por ato janë gjithashtu më të vështira për t'u shkruar. Pra, në shumicën e rasteve, kur emrat e pronave janë të njohur dhe të thjeshtë, përdoret një pikë. Dhe nëse keni nevojë për diçka më komplekse, atëherë kaloni në kllapa katrore.

Rezervimi i fjalëve

Një variabël nuk mund të ketë një emër të barabartë me një nga fjalët e rezervuara si "for", "let", "kthim", etj. Por kur renditni objektet JavaScript, nuk ka një kufizim të tillë.


Në parim, çdo emër lejohet, por ka një të veçantë: ai "__proto__" merr trajtim të veçantë për arsye historike. Për shembull, nuk mund ta vendosni në një vlerë tjetër përveç një objekti:

obj.__proto__ = 5;

alarm (obj.__proto__); // nuk funksionoi siç ishte menduar

Siç mund ta shihni nga kodi, qëllimi i primitive 5 është injoruar. Ky mund të jetë një burim gabimesh dhe madje dobësish nëse operatori synon të ruajë çifte arbitrare të vlerave kyçe në një objekt dhe të lejojë vizitorin të specifikojë çelësat. Në këtë rast, vizitori mund të zgjedhë "proto" si çelës dhe të shtojë JavaScript në objekt. Ekziston një mënyrë për të bërë objekte të trajtuara me __proto__ si një veti të rregullt. Ekziston edhe një hartë tjetër e strukturave të të dhënave që mbështesin çelësat arbitrarë.

Karakteristikat e numrave të plotë

Termi "veti numër i plotë" këtu nënkupton një varg që mund të konvertohet nga një numër i plotë pa modifikim. Kështu, për shembull, "49" është një emër i pronës me numër të plotë, sepse kur konvertohet në një numër të plotë dhe përsëri, është ende i njëjtë. Por "+49" dhe "1.2" nuk janë të tilla. Nga ana tjetër, nëse çelësat nuk janë numër i plotë, atëherë ato renditen sipas radhës që janë krijuar. Shembull më poshtë.


Për të rregulluar problemin me kodet e telefonimit, mund të "mashtroni" duke i bërë kodet jo të plota. Shtimi i një "+" (shenjë plus) përpara çdo kodi është i mjaftueshëm. Tani do të funksionojë siç është menduar.

Dallimi midis objekteve dhe primitivëve është se ato ruhen dhe kopjohen "me referencë". Vlerat primitive caktohen dhe kopjohen "si një vlerë e plotë". Një ndryshore ruan një "adresë në memorie" në vend të vetë objektit ose një "referencë" për të. Ju mund të përdorni çdo variabël për të hyrë dhe ndryshuar përmbajtjen e tij.


Shembulli i mësipërm tregon se ka vetëm një objekt dhe administrator për të hyrë në të. Pastaj, nëse më vonë përdoret një çelës (përdorues) tjetër, përdoruesi do të vërejë ndryshimet.

Operatorët e barazisë == dhe barazia strikte === për objektet funksionojnë në të njëjtën mënyrë. Dy objekte janë të barabarta vetëm nëse janë i njëjti objekt. Për krahasime si obj1 > obj2 ose krahasime me primitiven obj == 5, objektet shndërrohen në primitive. Për të qenë i sinqertë, krahasime të tilla nevojiten shumë rrallë dhe zakonisht janë rezultat i një gabimi kodimi.

Validimi i objektit në JavaScript

Objektet kanë akses në çdo pronë. Sidoqoftë, nëse nuk ekziston fare, nuk do të jetë një gabim. Vetëm qasja në një pronë joekzistente kthehet e papërcaktuar. Ai ofron një mënyrë shumë të zakonshme për të testuar një pronë dhe për ta krahasuar atë me një të papërcaktuar. Më poshtë është një shembull.


Përdorimi i "in" për pronat që ruajnë të papërcaktuara. Zakonisht një kontroll i rreptë krahasimi "=== i papërcaktuar" funksionon mirë. Ekziston një rast i veçantë kur dështon dhe "in" funksionon si duhet. Kjo është kur një veti e një objekti ekziston, por mbetet e papërcaktuar.


Në kodin e mësipërm, veçoria obj.test ekziston teknikisht. Prandaj operatori in punon si duhet. Situata si kjo janë shumë të rralla, sepse zakonisht nuk caktohet e papërcaktuara. Përdoren kryesisht vlera null "të panjohura" ose "boshe". Kështu, operatori in është efektivisht një mysafir në kod.

cikli "për..në".

Për të lëvizur nëpër të gjithë çelësat nga objekti në objekt, ekziston një formë e veçantë e ciklit: for..in. Kjo është një gjë krejtësisht e ndryshme nga konstrukti for(;;).

Më poshtë është një shembull.


Ju lutemi vini re se të gjithë konstruktorët "për" ju lejojnë të deklaroni një variabël looping brenda një cikli si një çelës letre. Përndryshe, në vend të kësaj, mund të përdorni një emër të ndryshëm ndryshoreje, çelës.

Për shembull, for(let prop në obj) përdoret gjithashtu gjerësisht.

Ekziston një "kllapë katrore" alternative që funksionon me çdo varg.


Çështja këtu kërkon që çelësat e objektit JavaScript të jenë një identifikues i vlefshëm i ndryshores, që do të thotë se nuk ka hapësira ose kufizime të tjera. Duhet pasur kujdes që të sigurohet që vija brenda kllapave të jetë cituar saktë. Kllapat katrore ofrojnë gjithashtu një mënyrë për të marrë emrin e pronës nga rezultati i çdo shprehjeje, në krahasim me një varg literal nga një ndryshore:

let key = "pëlqen zogjtë";

// njëjtë si përdoruesi["like birds"] = e vërtetë;

përdorues = i vërtetë.

Këtu ndryshorja kryesore mund të llogaritet në kohën e ekzekutimit dhe varet nga hyrja e përdoruesit dhe më pas përdoret për të aksesuar pronën. Kjo u jep programuesve më shumë fleksibilitet. Shënimi i pikave nuk mund të përdoret në një mënyrë të ngjashme, pasi do të përsëritej mbi objektin JavaScript. Më poshtë është një shembull.


Konst objekt

Një objekt konst i deklaruar mund të modifikohet. Një shembull është dhënë më poshtë.


Mund të duket sikur objekti JavaScript në linjë (*) do të shkaktonte një gabim, por nuk është kështu. Kjo është për shkak se const kap vlerën e vetë përdoruesit. Dhe këtu përdoruesi mban një referencë për të njëjtin objekt gjatë gjithë kohës. Linja (*) shkon brenda objektit, nuk i ricaktohet përdoruesit. Const do të japë një gabim nëse përpiqeni të vendosni përdoruesin dhe diçka tjetër. Klonimi dhe bashkimi, Object.assign krijon një referencë tjetër për të njëjtin objekt nëse duhet të dyfishohet. Kjo është gjithashtu e realizueshme, por pak më e vështirë sepse JavaScript nuk ka një metodë të integruar. Në fakt, kjo është rrallë e nevojshme. Kopjimi me referencë përdoret në shumicën e rasteve. Por nëse vërtet keni nevojë për këtë, atëherë duhet të krijoni një objekt JavaScript dhe të kopjoni strukturën e një ekzistuese, duke kopjuar vetitë e tij në një nivel primitiv. Më poshtë është një shembull.


Dhe gjithashtu mund të përdorni metodën Object.assign për këtë. Argumentet dest dhe src1, ..., srcN janë objekte. Ai kopjon vetitë e të gjitha objekteve src1, ..., srcNINTO dest. Me fjalë të tjera, vetitë e të gjitha argumenteve, duke filluar nga i dyti, kopjohen në 1. Pastaj kthehet në destinacion. Për shembull, mund ta përdorni për të kombinuar disa objekte në një.


Dhe mund të përdorni gjithashtu Object.assign për të zëvendësuar ciklin e thjeshtë të klonit. Ai kopjon të gjitha vetitë e përdoruesit në një objekt bosh dhe e kthen atë, ashtu si një lak, por më i shkurtër. Deri më tani, është supozuar se të gjitha vetitë e përdoruesit janë primitive. Por vetitë mund të jenë referenca për objekte të tjera.

Për ta rregulluar këtë, duhet të përdorni një lak kloni që kontrollon çdo vlerë të përdoruesit dhe, nëse është një objekt, atëherë përsërit strukturën e tij. Ky quhet "klonim i thellë".

Ekziston një algoritëm standard i klonimit të thellë që trajton rastin e mësipërm dhe rastet më komplekse të quajtur algoritmi i klonimit të strukturuar. Për të shmangur rishpikjen e rrotës, mund të përdorni një zbatim pune nga biblioteka lodash JavaScript, metoda quhet _.cloneDeep(obj).

Metodat e avancuara

Nëse një programues rrotullohet mbi një objekt dhe dëshiron të marrë të gjitha vetitë në të njëjtin rend që janë shtuar, ai mund të mbështetet në "renditjen e veçantë", ku vetitë e numrave të plotë renditen dhe të tjerat formohen në rendin në të cilin është krijuar objekti JavaScript. .

Metodat e avancuara të objekteve merren me koncepte që përdoren rrallë në JavaScripting. Kjo është për shkak se në skenarë normalë këto karakteristika të fuqishme nuk janë të nevojshme. Disa nga këto metoda mund të mos funksionojnë në shfletues të vjetër, siç janë lëshimet e hershme të Netscape 4.

Prototipi mund të përdoret për të krijuar objekte JavaScript dhe të gjitha metodat e mycircle, jo vetëm ato të reja. Kjo ka një ndikim të përzier të performancës. Ata nuk duhet të ruajnë kopje të veçanta të metodave për çdo shembull të objektit, kështu që mund të kërkojnë më pak memorie për t'u përdorur, por shfletuesi duhet të kërkojë shtrirjen aktuale dhe mëmë për t'i gjetur ato. Kjo mund të rezultojë në vonesë ekstreme. Në përgjithësi, përdoruesi duhet të përdorë atë që është e përshtatshme për kodin në vend që ta bazojë atë vendim në performancën, përveç nëse kanë të bëjnë me një mjedis të kontrolluar shumë specifik.


Kthehu i vërtetë

Në disa raste, mund të jetë e nevojshme që vetia e një objekti të lidhet me vetë objektin ose diku në zinxhirin e prototipit. Në JavaScript, të gjithë objektet përdorin metodën hasOwnProperty, e cila kthehet në të vërtetë nëse ajo veti është e lidhur me një shembull të një objekti individual. Në këtë rast, bëhet e mundur të kontrollohet nëse konstruktori i një objekti ka të njëjtën veti me të njëjtën vlerë si vetë shembulli i objektit. Kjo mund të japë rezultate të pasakta nëse ka veçori të veçanta të objektit JavaScript me të njëjtën vlerë si për shembullin e objektit ashtu edhe për prototipin e qarkut. Metoda hasOwnProperty merr një parametër të vetëm - emrin e pronës si varg.


Ju mund të krijoni metoda private në një mënyrë të ngjashme. Është thjesht një funksion që krijohet brenda një funksioni konstruktor. Kjo mund të duket konfuze për disa, por kjo është se si funksionon. Një funksion privat mund të thirret vetëm nga vetë konstruktori ose nga metodat që përcaktohen në linjë. Ato mund të përdoren si metoda publike nëse i caktohen një konstruktori publik dhe aksesohen duke përdorur metoda publike të objekteve Javascript.

funksioni myob() (funksioni cantBeSeen() ( alert(secretValue);

) var secretValue = "";

this.method1 = funksion () ( secretValue = "pa surpriza";!}

kjo.metoda2 = cantBeSeen;

) var oneOb = myob i ri();

oneOb.metoda1();

//lajmëron "pa surpriza" oneOb.method2();

//lajmëron "pa surpriza".

Modeli i komandës

Objektet e komandës lejojnë sisteme të lidhura lirshëm duke i ndarë ato që lëshojnë një kërkesë nga objektet dhe ato që aktualisht e përpunojnë kërkesën. Këto kërkesa quhen ngjarje, dhe kodi që përpunon kërkesat quhet mbajtës i ngjarjeve.

Supozoni se po krijoni aplikacione që mbështesin veprimet e clipboard-it Cut, Copy dhe Paste. Këto veprime mund të aktivizohen në mënyra të ndryshme në të gjithë aplikacionin: nga një sistem menyje, një meny konteksti si klikimi me të djathtën në një fushë teksti ose një shkurtore tastierë. Objektet e komandës ju lejojnë të centralizoni përpunimin e këtyre veprimeve, një për çdo operacion, kur nevojitet vetëm një komandë për të përpunuar të gjitha kërkesat e Cut, një për të gjitha kërkesat e Kopjimit dhe një për të gjitha kërkesat Paste.

Për shkak se ekipet centralizojnë të gjithë përpunimin, ato shpesh përfshihen edhe në trajtimin e funksioneve të zhbërjes për të gjithë aplikacionin. Përmirësime të rëndësishme mund të arrihen duke aplikuar teknika moderne JavaScript, duke rezultuar në aplikacione më efikase, më të besueshme dhe të mirëmbajtura.

Për të mësuar se si ta bëni këtë, mund të përdorni shabllonet JavaScript + jQuery. Kjo paketë unike përfshin JavaScript të optimizuar për të gjithë shabllonet GoF duke përdorur veçori më të avancuara si hapësirat e emrave, prototipet, modulet, objektet e funksionit, mbylljet, funksionet anonime dhe më shumë. Nëse përdoruesit kanë nevojë për mjetet dhe teknikat më të fundit për shabllonet JavaScript, shabllonet jQuery dhe arkitekturat e shablloneve, atëherë ky është rasti më i mirë i përdorimit. Kjo paketë përmban informacion të vlefshëm dhe të përditësuar për zhvilluesit e JavaScript. Ja çfarë përfshihet:

  1. Modele GoF të optimizuara nga JavaScript.
  2. Modelet moderne të dizajnit JavaScript.
  3. Modelet-View Design Modelet.
  4. Modelet e dizajnit jQuery.
  5. Modelet arkitekturore të idiomave JavaScript.
  6. Shembuj të aplikacioneve (MVC, SPA, etj.)

Bazat e propozuara të sintaksës së objekteve JavaScript janë shumë të rëndësishme për programuesit fillestarë. Fillimisht duhet kuptuar objektet, pastaj do të ketë njohuri për programimin e orientuar drejt objekteve. Është thelbësore të kemi një kuptim të thellë të këtij materiali pasi ai shërben si bazë për pjesën tjetër të gjuhës JavaScript.




Objektet janë një nga konceptet thelbësore në JavaScript. Kur fillova t'i studioja për herë të parë, më dukeshin mjaft të thjeshta: vetëm çifte çelësash dhe vlerash, siç përshkruhen në teori.

Vetëm pas ca kohësh fillova të kuptoj se tema ishte shumë më komplekse nga sa mendoja. Dhe pastaj fillova të studioj informacione nga burime të ndryshme. Disa prej tyre dhanë një ide të mirë të temës, por unë nuk arrita ta shikoja të gjithë foton menjëherë.

Në këtë postim u përpoqa të mbuloj të gjitha aspektet e punës me objekte në JS, pa u thelluar shumë në detaje specifike, por edhe pa lënë mënjanë detaje të rëndësishme që do t'ju ndihmojnë të kuptoni temën dhe të ndiheni më të sigurt ndërsa e studioni më tej.

Pra, le të fillojmë me bazat.

Nje objekt

Një objekt në JavaScript është thjesht një koleksion i vetive, secila prej të cilave është një çift çelës-vlerë. Ju mund të përdorni çelësat duke përdorur një pikë ( obj.a) ose shënimi i kllapave ( obj ["a"]).

Mos harroni se kllapat duhet të përdoren nëse çelësi është:

  • nuk është një identifikues i vlefshëm JavaScript (ka një hapësirë, një vizë, fillon me një numër...)
  • është një variabël.
Një nga vetitë që objektet në JS marrin kur krijohen quhet Prototip, dhe ky është një koncept shumë i rëndësishëm.

Prototip

Çdo objekt në JavaScript ka një veti të brendshme të quajtur Prototip. Në shumicën e shfletuesve ju mund t'i referoheni me shënimin __proto__.

Prototipështë një mënyrë për të zbatuar trashëgiminë e pronës në JavaScript. Në këtë mënyrë ju mund të ndani funksionalitetin pa dublikuar kodin në memorie. Metoda funksionon duke krijuar një lidhje midis dy objekteve.

E thënë thjesht, Prototype krijon një tregues nga një objekt në tjetrin.

Zinxhiri prototip

Sa herë që JS kërkon një pronë në një objekt dhe nuk e gjen atë drejtpërdrejt në vetë objektin, ai kontrollon praninë e pronës në objektin prototip. Nëse nuk ka pronë në të, atëherë JS do të vazhdojë të shikojë në prototipin e objektit të lidhur. Kjo do të vazhdojë derisa JS të gjejë një pronë të përshtatshme ose të arrijë në fund të zinxhirit.

Le të shohim një shembull:

Var cons = funksion () ( this.a = 1; this.b = 2; ) var obj = new cons(); kundër.prototipi.b = 3; kundër.prototipi.c = 4;
kundërështë një konstruktor (thjesht një funksion që mund të thirret duke përdorur operatorin i ri).

Në rreshtin e pestë ne krijojmë një objekt të ri - një kopje të re kundër. Menjëherë pas krijimit obj gjithashtu merr pronësinë prototip.

Dhe tani ne shtojmë vetitë ( "b", "c") prototipi i objektit kundër.
Le të shqyrtojmë obj:

obj.a // 1- Gjithçka është e njëjtë këtu, obj.a eshte akoma 1.
obj.c?- y obj asnjë pronë c! Sidoqoftë, siç u përmend më parë, JS tani do ta kërkojë atë në prototip obj dhe do të kthejë vlerën 4.

Tani le të mendojmë se cili është kuptimi obj.b dhe si do të jetë kur ta heqim obj.b?

Obj.bështë e barabartë me 2. Ne ia caktuam pronën b, por ne e bëmë atë për një prototip kundër, kështu që kur kontrollojmë obj.b, atëherë ne ende marrim 2. Megjithatë, menjëherë pas heqjes obj.b JS nuk do të jetë më në gjendje të gjejë b y o bj, dhe për këtë arsye do të vazhdojë kërkimin në prototip dhe do të kthejë vlerën 3.

Krijimi i një objekti

Fjalë për fjalë objekti: le të obj = (a: 1);
Ne krijuam një objekt me zinxhirin prototip të mëposhtëm: obj ---> Objekti.prototip ---> null
Siç mund ta merrni me mend, objekt.prototipështë prototipi i objektit, dhe gjithashtu fundi i zinxhirit prototip.

Object.create():var newObj = Objekti.krijoj(obj);
U i riObj do të ketë zinxhirin e mëposhtëm të prototipeve: newObj ---> obj ---> Objekti.prototip ---> null

Konstruktor. Ashtu si në shembullin e mësipërm, konstruktori është thjesht një funksion JS që na lejon të përfitojmë nga operatori i ri për të krijuar shembuj të rinj të tij.

Klasat ES6:

Klasa drejtkëndësh ( konstruktor (lartësi, gjerësi) ( this.height = lartësi; this.width = gjerësi; ) getArea() ( return this.height * this.width; ) ) le katror = drejtkëndësh i ri (2, 2);
Sheshi- shembulli i konstruktorit drejtkëndësh, dhe kështu mund të telefonojmë katror.getArea() //4, katror.gjerësia, si dhe të gjitha funksionet e trashëguara nga objekt.prototip.

Cila mënyrë është më e mirë? Nëse planifikoni të krijoni shembuj të shumtë, mund të përdorni ES6 ose projektuesin. Nëse planifikoni të krijoni një objekt një herë, atëherë është më mirë të specifikoni një fjalë për fjalë, pasi kjo është mënyra më e thjeshtë.

Dhe tani që kemi mësuar për prototip dhe pasi jemi njohur me të gjitha mënyrat për të krijuar objekte të reja, ne mund të vazhdojmë të diskutojmë një nga aspektet më konfuze që lidhen me objektet.

Krahasoni dhe ndryshoni objektet

Në JavaScript, objektet janë të llojit të referencës

Kur krijojmë një objekt le të obj = (a: 1);, e ndryshueshme obj merr adresën e memories së objektit, por jo vlerën e tij! Është jashtëzakonisht e rëndësishme të kuptohet ky ndryshim, përndryshe mund të ndodhin gabime. Kur krijojmë një objekt tjetër le newObj = obj, ne në fakt po krijojmë tregues në një zonë të caktuar memorie obj, dhe jo një objekt krejtësisht i ri.

Kjo do të thotë se duke bërë newObj.a = 2, ne në fakt ndryshojmë obj kështu që obj.a bëhet e barabartë me 2!

Kjo qasje çon lehtësisht në gabime, kjo është arsyeja pse shumë kompani punojnë me objekte të pandryshueshme. Në vend që të ndryshoni një objekt të krijuar tashmë, do të duhet të krijoni përsëri një objekt të ri (një kopje të origjinalit) dhe të bëni ndryshime në të. Kështu funksionojnë bibliotekat e rëndësishme si Redux, dhe është një nga konceptet thelbësore të programimit funksional në përgjithësi. Mund të lexoni më shumë.

Barazia

Nga sa më sipër rezulton gjithashtu se dy objekte nuk mund të jenë kurrë të barabartë, edhe nëse kanë të njëjtat veti. Kjo është për shkak të faktit se JS në fakt krahason vendndodhjen e memories së objekteve, dhe dy objekte nuk janë kurrë në të njëjtin vend memorie.

// Dy objekte të dallueshme me të njëjtat veti nuk janë të barabarta var fryt = (emri: "mollë"); var fruitbear = (emri: "mollë"); fruta === frutore; // kthej false // këtu fruti dhe frutari po tregojnë të njëjtin objekt var fryt = (emri: "mollë"); var frutore = fruta; fruta === frutore; // kthehu i vërtetë
Pra, me shumë mundësi tashmë keni pyetur veten se si mund t'i krahasoni objektet ose si të kryeni manipulime të ndryshme me objekte, duke pasur parasysh kërkesën për pandryshueshmërinë e tyre.

Le të shqyrtojmë disa mundësi.

Ndryshimi i një objekti

Le të themi se është e qartë se në fakt nuk duhet të ndryshojmë objekte, kështu që duam të krijojmë një kopje të objektit përkatës dhe të ndryshojmë vetitë e tij. Vjen në shpëtim Object.assign().

Var obj = (a: 1, b: 2); var newObj = Object.assign((), obj,(a:2)) // (a: 2, b: 2 )
Nëse duam të ndryshojmë vlerën e pronës a Objekt obj, ju mund të përdorni objekt.caktoj për të krijuar një kopje obj dhe ndryshimet e tij.

Në shembull mund të shihni se ne fillimisht krijojmë një objekt bosh, pastaj kopjojmë vlerat obj dhe të bëjmë ndryshimet tona, duke marrë përfundimisht një objekt të ri dhe të gatshëm për përdorim.

Ju lutemi vini re se kjo metodë nuk do të funksionojë për kopjim të thellë. Kur flasim për kopjim të thellë, nënkuptojmë se duhet të kopjojmë një objekt me një ose më shumë veti.

Const obj = (a: 1, b: (a: 1 ) ); // b vetia është një objekt
Object.assign() kopjon vetitë e një objekti, kështu që nëse vlera e vetive është një tregues në një objekt, atëherë kopjohet vetëm treguesi.

Një kopje e thellë kërkon një operacion rekurziv. Këtu mund të shkruani një funksion ose thjesht të përdorni një metodë _.cloneDeep nga biblioteka Lodash.

Krahasimi i objekteve

Ekziston një teknikë interesante për të punuar me objekte - konvertimi i vargut. Në shembullin e mëposhtëm, ne i konvertojmë të dy objektet në vargje dhe i krahasojmë ato:

JSON.stringify(obj1) === JSON.stringify(obj2)
Kjo qasje ka kuptim sepse ne përfundojmë duke krahasuar vargjet që janë një tregues për një lloj vlere. Lajmi i keq është se jo gjithmonë funksionon, kryesisht sepse rendi i vetive të objektit nuk është i garantuar.

Një zgjidhje tjetër e mirë është përdorimi i metodës _.është e barabartë nga Lodash, i cili kryen krahasimin e objekteve të thella.

Dhe para se të përfundojmë, le të kalojmë disa pyetje të bëra shpesh rreth objekteve. Kjo do t'ju ndihmojë të zhyteni më thellë në temë dhe të zbatoni njohuritë e marra në praktikë.

Përpiquni të mendoni vetë për zgjidhjen përpara se të lexoni përgjigjen.

Si të zbuloni gjatësinë e një objekti?

Për të marrë përgjigjen, duhet të kaloni një nga një të gjitha vetitë e objektit dhe t'i numëroni ato. Ka disa mënyra për të kryer një përsëritje të tillë:
  • për në. Kjo metodë mbulon të gjitha vetitë e numërueshme të një objekti dhe zinxhirët e tij prototip. Ne e kemi parë prototipin (dhe shpresojmë të kemi mësuar materialin), kështu që duhet të jetë e qartë se aplikacioni për në nuk do të jetë gjithmonë e vërtetë për marrjen e vetive të një objekti.
  • Objekti.çelësat. Kjo metodë kthen një grup me çelësat e të gjithëve vet(që i përkasin objektit të specifikuar) duke numëruar Vetitë. Kjo qasje është më e mirë sepse ne punojmë vetëm në vetitë e objektit, pa i aksesuar vetitë prototip. Megjithatë, ka situata ku ju keni caktuar një atribut të numërueshme disa prona janë të rreme, dhe objekt.çelësat përfundon duke e anashkaluar atë dhe ju merrni një rezultat të pasaktë. Kjo ndodh rrallë, por në raste të tilla do të jetë e dobishme getOwnPropertyNames.
  • getOwnPropertyNames kthen një grup që përmban gjithçka vetçelësat e objekteve (të numërueshëm dhe të panumërueshëm).
Gjithashtu vlen të përmendet:
  • Objekti.vlerat përsërit mbi vetitë e veta të numërimit dhe kthen një grup me përkatësinë vlerat.
  • Objekti.hyrjet përsërit mbi vetitë e tij të numërimit dhe kthen një grup me çelësat dhe vlerat e tyre.
Mendoj se keni vënë re se shumica e metodave të listuara më sipër kthejnë një grup. Kjo është një mundësi për të përfituar plotësisht nga teknikat e grupeve të JavaScript.

Një metodë e tillë është varg.gjatësia. Si rezultat, ne thjesht mund të shkruajmë

Lëreni objLength = Object.getOwnPropertyNames(obj).length;

Si të kontrolloni nëse një objekt është bosh?

  1. JSON.stringify(myObj) === "()"?. Këtu ne përsëri përdorim mjetin e konvertimit të vargut për të kontrolluar me lehtësi nëse një objekt është bosh (duke krahasuar vargjet, jo objektet).
  2. !Objekt.çelësat(myobj).gjatësia // e vërtetë?.? Siç e përmenda, konvertimi i çelësave të objekteve në një grup mund të jetë shumë i dobishëm. Këtu ne përdorim pronën e përshtatshme gjatësia, i trashëguar nga Vargu.prototip, duke e përdorur atë për të kontrolluar gjatësinë e tasteve në grup. Në JS 0 kthehet në false, pra duke shtuar ! ne e kthejmë atë në të vërtetë. Çdo numër tjetër do të konvertohet në fals.

Së fundi

Shpresoj që tani të ndiheni më të sigurt në krijimin dhe punën me objekte. Le të përmbledhim:
  • Mos harroni se objektet janë të një lloji referencë, që do të thotë se rekomandohet të punoni me ta pa ndryshuar objektet origjinale.
  • Bëni miq me pronën prototip dhe një zinxhir prototipash.
  • Njihuni me mjetet që ju ndihmojnë të punoni me objekte. Mos harroni se ju mund t'i ktheni objektet në vargje, të merrni një grup të çelësave të tyre ose thjesht të përsërisni mbi vetitë e tyre duke përdorur grupin e metodave me të cilat jemi prezantuar.
Fat të mirë në mësimin e objekteve JavaScript.

Në këtë artikull, unë dua të flas sa më plotësisht dhe në mënyrë të vazhdueshme që të jetë e mundur se çfarë është një objekt në JavaScript, cilat janë aftësitë e tij, cilat marrëdhënie mund të ndërtohen midis objekteve dhe cilat metoda të trashëgimisë "vendase" rrjedhin nga kjo, si ndikon e gjithë kjo performanca dhe çfarë të bëjmë në përgjithësi me gjithë këtë :)

Artikulli NUK do të ketë fjalë për: emulimin e paradigmës tradicionale të objektit të klasës, sheqerin sintaksor, mbështjellësit dhe kornizat.

Kompleksiteti i materialit do të rritet nga fillimi deri në fund të artikullit, kështu që për profesionistët pjesët e para mund të duken të mërzitshme dhe banale, por më pas do të jenë shumë më interesante :)

Objektet në JavaScript

Shumë artikuj përmbajnë shprehjen "Në JavaScript, gjithçka është një objekt". Teknikisht kjo nuk është plotësisht e vërtetë, por u bën përshtypjen e duhur fillestarëve :)

Në të vërtetë, shumë në gjuhë është një objekt, madje edhe ajo që nuk është objekt mund të ketë disa nga aftësitë e saj.

Është e rëndësishme të kuptohet se fjala "objekt" përdoret këtu jo në kuptimin e "një objekti të një klase". Një objekt në JavaScript është para së gjithash vetëm një koleksion i vetive (nëse preferoni, mund ta quani atë një grup ose listë shoqëruese) i përbërë nga çifte çelës-vlerë. Për më tepër, çelësi mund të jetë vetëm një varg (edhe për elementët e grupit), por vlera mund të jetë çdo lloj i të dhënave të listuara më poshtë.

Pra, në JavaScript ka 6 llojet bazë të dhënat janë të Papërcaktuara (duke treguar mungesën e një vlere), Null, Boolean (Boolean), String (string), Number (numër) dhe Object (objekt).
Për më tepër, 5 të parat janë primitive llojet e të dhënave, por Objekti nuk është. Për më tepër, në mënyrë konvencionale mund të konsiderojmë se lloji Object ka "nëntipe": grup (Array), funksion (Funksion), shprehje e rregullt (RegExp) dhe të tjera.
Ky është një përshkrim disi i thjeshtuar, por në praktikë zakonisht është i mjaftueshëm.

Për më tepër, llojet primitive String, Number dhe Boolean lidhen në mënyra të caktuara me "nënllojet" joprimitive të Object: String, Number dhe Boolean, respektivisht.
Kjo do të thotë që vargu "Hello, world", për shembull, mund të krijohet ose si vlerë primitive ose si objekt String.
Me pak fjalë, kjo bëhet në mënyrë që programuesi të mund të përdorë metoda dhe veti kur punon me vlera primitive sikur të ishin objekte. Ju mund të lexoni më shumë rreth kësaj në seksionin përkatës të këtij artikulli.

Punoni nga lidhja

Një referencë është një mjet për të hyrë në një objekt me emra të ndryshëm. Puna me çdo objekt kryhet ekskluzivisht me referencë.
Le ta demonstrojmë këtë me një shembull:
test= funksioni () (alarm ("Përshëndetje!" )) //Krijoni një funksion (alarm("Përshëndetje!")) (dhe një funksion, siç e kujtojmë, është një objekt i plotë) dhe bëni variablin e testit një referencë për të
test_link=test; //test_link tani i referohet edhe funksionit tonë
test (); //Përshëndetje!
test_lidhja (); //Përshëndetje!


Siç mund ta shohim, si lidhja e parë ashtu edhe e dyta japin të njëjtin rezultat.
Ne duhet të kuptojmë se nuk kemi asnjë funksion të quajtur test, dhe se ndryshorja e testit nuk është një lloj lidhjeje "kryesore" ose "primare" dhe "test_link" është e vogël.

Funksioni ynë, si çdo objekt tjetër, është thjesht një zonë në memorie, dhe të gjitha referencat për këtë zonë janë absolutisht ekuivalente. Për më tepër, objekti mund të mos ketë fare referenca - në këtë rast quhet anonim dhe mund të përdoret vetëm menjëherë pas krijimit (për shembull, kalohet në një funksion), përndryshe do të jetë e pamundur t'i qaseni atij dhe së shpejti do të të shkatërrohet nga mbledhësi i mbeturinave (grumbullimi i mbeturinave), i cili është përgjegjës për fshirjen e objekteve pa referenca.

Le të shohim pse është kaq e rëndësishme ta kuptojmë këtë:

test=(prop: "një tekst") //Krijoni një objekt me vetinë prop
test_link=test; //Krijoni një lidhje tjetër për këtë objekt

Alert(test.prop); //ndonjë tekst

//Ndrysho vetinë e objektit
test_link.prop="newtext" ;

Alert(test.prop); //newtekst
alarm (test_link.prop); //newtekst
/*Dikush mund të thotë se prona ka ndryshuar edhe këtu edhe atje - por kjo nuk është kështu.
Ka vetëm një objekt. Pra, prona ndryshoi në të një herë, dhe lidhjet thjesht vazhdojnë të tregojnë aty ku tregojnë. */

//Shto një pronë të re dhe hiq të vjetrën
test.new_prop="përshëndetje" ;
fshij test.prop;

Alert(test_link.prop); //i papërcaktuar - kjo pronë nuk ekziston më
alarm (test_link.new_prop);

//Fshi lidhjen
fshij testin;
alarm (test.prop_i ri);
/*Në këtë pikë skripti do të hedhë një gabim, sepse testi nuk ekziston më, dhe test.new_prop nuk ekziston aq më tepër */
alarm (test_link.new_prop); //Përshëndetje
/* por këtu gjithçka është në rregull, sepse ne nuk e fshimë vetë objektin, por vetëm një lidhje me të. Tani objekti ynë tregohet nga një lidhje e vetme, test_link */

//Krijoni një objekt të ri
test=test_link; //Së pari, krijoni përsëri lidhjen e provës
test_link=(propozim: "disetext" ) //Dhe këtu është objekti i ri

Alert(test_link.prop); //ndonjë tekst
alert(test.prop); //i papërcaktuar
/* Krijimi i një objekti të ri prish lidhjen e referencës, dhe tani testi dhe test_link tregojnë objekte të ndryshme.
Në fakt, kjo është e barabartë me fshirjen e test_link dhe krijimin e saj përsëri, por duke treguar një objekt tjetër */
alarm (test.prop_i ri); //përshëndetje - testi tani përmban një lidhje me objektin tonë të parë


* Ky kod burim u theksua me theksuesin e kodit burimor.

Kjo sjellje e objekteve shpesh ngre shumë pyetje për zhvilluesit fillestarë, kështu që shpresoj se ky tekst do të sjellë pak qartësi. Nëse duam të krijojmë një kopje vërtet të re, të pavarur të një objekti, dhe jo një lidhje, atëherë e vetmja mënyrë për ta bërë këtë është të krijojmë një objekt të ri dhe të kopjojmë vetitë e kërkuara atje.

Vlen gjithashtu të theksohet se puna me objekte me referencë, përveç efekteve argëtuese të listuara më sipër, siguron gjithashtu kursime të konsiderueshme të memories, gjë që është e rëndësishme kur një objekt përdoret gjerësisht në vende të ndryshme në program.

Vlerat primitive

Siç e përmenda më lart, llojet e të dhënave String dhe Number mund të jenë ose objekte ose vlera primitive.
obj= string i ri ("përshëndetje"); //Krijoni një varg si objekt
thjeshtë = "përshëndetje" ; //Krijoni një vlerë primitive

Alert(obj); //Përshëndetje
alarm (i thjeshtë); //përshëndetje - deri më tani gjithçka është e parashikueshme

Alert(obj.length); //6 - një objekt i tipit String ka një veçori gjatësi që ruan gjatësinë e vargut
alarm (i thjeshtë.gjatësi); //6
/* Edhe pse thjeshtë nuk është një objekt, ne mund të aksesojmë të njëjtin grup vetish si një objekt i tipit String. Është mjaft i përshtatshëm */

Obj.prop="tekst" ;
thjeshtë.prop="tekst" ;

Alert(obj.prop); //tekst - meqenëse obj është një objekt i rregullt, ne mund t'i japim lehtësisht një veçori tjetër
alarm (i thjeshtë. mbështetës); //i papërcaktuar - por thjeshtë nuk është një objekt, dhe ky numër nuk do të funksionojë për ne

* Ky kod burim u theksua me theksuesin e kodit burimor.


E njëjta gjë është e vërtetë për të dy llojet Number dhe Boolean (mirë, përveç se ata nuk kanë një veçori gjatësie, por kanë një numër karakteristikash të tjera të shkëlqyera).
Përdorimi i vargjeve dhe numrave si objekte nuk ka ndonjë përfitim praktik, sepse vlerat primitive janë më të përshtatshme për t'u përdorur, por në të njëjtën kohë ruajnë të gjithë funksionalitetin e nevojshëm. Megjithatë, për të përfunduar tablonë është e nevojshme të kuptohet ky mekanizëm.

Mos e ngatërroni përdorimin e vlerave primitive me përdorimin e fjalëve - për shembull, nëse krijojmë një grup si "test=new Array()" ose si "test=", rezultati do të jetë ende i njëjti objekt. Nuk do të marrim asnjë vlerë primitive.

Krijimi dhe përdorimi i objekteve

Pra, ndryshe nga gjuhët që zbatojnë paradigmën klasë-objekt, ne nuk kemi nevojë të krijojmë një klasë dhe më pas të krijojmë një objekt të klasës. Ne mund të krijojmë menjëherë një objekt, gjë që do të bëjmë në shembullin e mëposhtëm:
test=(
simple_property: "Përshëndetje" ,
pronë_objekti: (
përdorues_1: "Petya" ,
përdorues_2: "Vasya"
},
funksioni_properti: funksioni (përdoruesi) (
alert(this .property_simple + ", " + this .object_property);
}
}

Test.funksioni_property("përdoruesi_1"); //Përshëndetje, Petya.

* Ky kod burim u theksua me theksuesin e kodit burimor.


Kemi një objekt provë që ka 3 veti, emrat e të cilave, shpresoj, flasin vetë. Ajo që na intereson më shumë për të është funksioni_properti, i cili përmban funksionin. Një funksion i tillë mund të quhet metodë objekti.

Funksioni ynë përdor dy herë fjalën kyçe this, e cila është një tregues (d.m.th., një referencë) për objektin nga i cili thirret funksioni. Kështu, this.simple_property=test.simple_property="Përshëndetje", dhe this.object_property=test.object_property="Peter".

Është e rëndësishme të jemi të qartë se kjo gjithmonë tregon për objektin nga i cili thirret funksioni, dhe jo për objektin të cilit i përket. Edhe pse në këtë shembull janë i njëjti objekt, nuk është gjithmonë kështu.

test.funksioni_property("përdoruesi_1"); //Përshëndetje, Petya.

Test2=Objekt i ri(); //Një formë tjetër e krijimit të një objekti të ri, i ngjashëm me test2=()

Test.function_property.call(test2, "user_1" ); //gabim
/* Metoda e thirrjes ju lejon të thërrisni një funksion në emër të një objekti tjetër. Në këtë rast, ne e quajmë metodën function_property të objektit testues, dhe kjo nuk tregon më për objektin e testimit, por për objektin test2. Dhe sepse nuk ka vetinë object_property, atëherë kur të përpiqeni të merrni this.object_property skripti do të hedhë një gabim */

//le të përpiqemi të rregullojmë situatën
test2.simple_property="Ditë të mirë" ;
test2.objekti_properti=test.properti_objekti; //Në këtë rast, ne do të përdorim specifikimin e objektit me referencë në mënyrë që të mos dublikojmë kodin

Test.function_property.call(test2, "user_1" ); //Mirëdita, Petya.


* Ky kod burim u theksua me theksuesin e kodit burimor.

Nga shembulli duhet të jetë gjithashtu e qartë se nuk ka hapa të qartë për krijimin dhe përdorimin e një objekti. Një objekt mund të modifikohet në çfarëdo mënyre në çdo kohë - para, pas dhe madje edhe gjatë përdorimit. Ky është gjithashtu një ndryshim i rëndësishëm nga OOP "tradicional".

Konstruktor

Në shembullin e mësipërm, ne krijuam 2 objekte që kishin disa ngjashmëri. Të dyja kishin veti simple_property dhe object_property. Natyrisht, kur shkruani kod real, shpesh lind detyra për të krijuar objekte identike ose thjesht të ngjashme. Dhe sigurisht, nuk kemi pse ta krijojmë çdo objekt të tillë me dorë.

Një stilist do të na vijë në ndihmë. Një konstruktor në JavaScript nuk është pjesë e një klase (sepse nuk ka klasa), por thjesht një funksion më vete. Funksioni më i zakonshëm.

bëj_me= funksioni (_name) (
alarm ("Unë u lëshova");
ky .emri=_emri;

}


/* Le të kuptojmë se çfarë po ndodh këtu. Përkthyesi sheh operatorin e ri dhe kontrollon se çfarë është në të djathtë të tij. Sepse make_me është një funksion, dhe mund të përdoret si konstruktor, pastaj krijohet një objekt i ri në memorie dhe funksioni make_me lëshohet për ekzekutim, dhe kjo tregon pikërisht këtë objekt të ri. Më pas, ky objekt shtohet me një veçori name, të cilës i caktohet vlera nga argumenti _name dhe një metodë show_name. Gjithashtu (nuk e di në cilën pikë, por nuk ka rëndësi) ndryshorja fëmijë fillon të tregojë te objekti ynë i ri, i sapolindur */

Alert (emri i fëmijës); //Vasya
fëmija.shfaq emrin(); //Vasya


fëmija2.shfaq emrin(); //Pjetri

Child2.show_name=funksion () (alarm( "Nuk do ta them emrin tim");} //Mos harroni se ne mund t'i ndryshojmë objektet tona në çdo kohë
fëmija2.shfaq emrin(); //Nuk do ta them emrin tim

Fëmija.shfaq emrin(); //Vasya - fëmijët nuk ndikojnë njëri-tjetrin në asnjë mënyrë


* Ky kod burim u theksua me theksuesin e kodit burimor.

Ju gjithashtu mund të krahasoni një stilist me një baba - ai lind një fëmijë, duke e pajisur atë me cilësi të caktuara, por menjëherë pas krijimit fëmija bëhet plotësisht i pavarur nga prindi dhe mund të bëhet shumë i ndryshëm nga vëllezërit e tij.
Nëse kujtojmë përshkrimin e llojeve të të dhënave në fillim të artikullit, bëhet e qartë se Objekti dhe nëntipet e tij (Funksioni, Array dhe të tjerët) janë në të vërtetë konstruktorë që i japin objektit të krijuar aftësitë e një funksioni, grupi, etj.

Pra, kjo tashmë është shumë më mirë. Tani kemi aftësinë për të krijuar objekte sipas një modeli. Megjithatë, ende nuk është gjithçka mirë. Së pari, çdo objekt që krijojmë dhe të gjitha vetitë dhe metodat e tij zënë një vend të veçantë në kujtesë, megjithëse në shumë mënyra ato përsëriten. Së dyti, çka nëse duam të ruajmë lidhjen midis prindit dhe fëmijës dhe të jemi në gjendje të ndryshojmë të gjitha objektet e fëmijës menjëherë. Një prototip do të na vijë në ndihmë.

Prototip

Ashtu si çdo fëmijë ka një baba dhe një nënë (të paktën në kuptimin biologjik), kështu ka çdo objekt në JavaScript. Dhe nëse babai, siç e kemi përcaktuar, punon si dizajner, atëherë nëna është pikërisht prototipi. Le të shohim se si ndodh kjo:
bëj_me= funksioni (_name) (
alarm ("Unë u lëshova");
ky .emri=_emri;
ky .show_name=funksion () (alarm(this .name);)
}
/*
Duke parë fjalën kyçe të funksionit, përkthyesi kontrollon kodin në të djathtë të tij, e kështu me radhë. gjithçka është në rregull - krijon një objekt të ri në memorie, i cili është gjithashtu funksioni ynë. Më pas, automatikisht (pa ndërhyrjen e programuesit) krijohet një tipar prototip për këtë funksion, i cili i referohet një objekti bosh. Nëse do ta bënim këtë me dorë, do të dukej si make_me.prototype=new Object();

Më pas, këtij objekti (të treguar nga vetia prototip) gjithashtu i jepet automatikisht një veti konstruktori, duke treguar përsëri funksionin. Rezulton se kjo është një lidhje ciklike.

Tani ky objekt, i cili mund të përshkruhet si (konstruktor: ... këtu është një referencë për një funksion...) është prototipi i funksionit.
*/

//Objekt - në të vërtetë, një objekt
alert(lloji make_me.prototip.konstruktor); //Funksioni është funksioni ynë
alert(make_me.prototype.constructor === make_me); //e vërtetë

//Shto një metodë të re në prototipin e funksionit make_me

Child=new make_me("Vasya"); //Isha nisur
/* Tani, përveç gjithçkaje të përshkruar në shembullin e mëparshëm, një veçori shtesë e fshehur [] krijohet në objektin fëmijë, i cili tregon të njëjtin objekt si make_me.prototype. Sepse Prona është e fshehur, ne as nuk mund ta shohim vlerën e saj dhe as ta ndryshojmë atë - megjithatë, ajo luan një rol të rëndësishëm në punën e mëtejshme */

Alert (emri i fëmijës); //Vasya
fëmija.shfaq emrin(); //Vasya

Child.set_emri ("Kolya" );
/* Së pari, përkthyesi kërkon metodën set_name në objektin fëmijë. Meqenëse nuk është aty, vazhdon të kërkojë në pronën e fëmijës.[, e gjen atje dhe e drejton. */
fëmija.shfaq emrin(); //Kolya - tani emri i Vasya është Kolya :)

Make_me.prototype.show_name2=funksion () (alarm("Përshëndetje, " + ky .emër;) //Sepse një prototip është një objekt i zakonshëm, po aq mirë mund ta ndryshojmë gjatë fluturimit

Child2=new make_me("Petya" );
fëmija2.shfaq emrin2(); //Përshëndetje, Petya
fëmija.shfaq emrin2(); //Përshëndetje, Kolya - ndryshimet në prototip prekin jo vetëm objektet e krijuara rishtazi, por edhe të gjitha ato të vjetra

Child2.show_name2=funksion () (alarm( "Nuk do ta them emrin tim");} //Ne ende mund ta ndryshojmë vetë objektin dhe metoda e re show_name2 në këtë objekt (dhe vetëm në të), si të thuash, do të "mbishkruan" metodën e vjetër nga prototipi
fëmija2.shfaq emrin2(); //Nuk do ta them emrin tim - sepse... tani kemi metodën tonë show_name2, pastaj thirret dhe kërkimi në prototip nuk ndodh

Fëmija.shfaq emrin2(); //Përshëndetje, Kolya - gjithçka është ende e njëjtë këtu

Make_me.prototype=(mbështetje: "përshëndetje" ) //Le të përpiqemi të rikrijojmë prototipin përsëri

Alert(fëmijë.prop); //i papërcaktuar
fëmija.shfaq emrin2(); //Përshëndetje Kolya
/* Nëse mbani mend se çfarë është puna me referencë, atëherë gjithçka është e qartë. Rikrijimi i prototipit prish lidhjen, dhe tani vetia [] e objekteve child dhe child2 tregojnë në një objekt (i cili më parë ishte prototipi i funksionit make_me), dhe vetia make_me.prototype tregon një objekt tjetër, i cili është i ri. prototipi i funksionit make_me */

Child3=new make_me("Oleg" );
alert(fëmijë3.prop); //përshëndetje - siç pritej


* Ky kod burim u theksua me theksuesin e kodit burimor.

Siç shihet nga shembulli, për sa kohë që babai i qëndron besnik nënës (d.m.th., për sa kohë që lloji i funksionit mbetet i njëjtë), të gjithë fëmijët varen nga nëna dhe janë të ndjeshëm ndaj të gjitha ndryshimeve të saj. Megjithatë, sapo prindërit divorcohen (dizenjuesi e ndryshon prototipin në një tjetër), fëmijët ikin menjëherë në të gjitha drejtimet dhe nuk ka më kontakt me ta.

Pak për terminologjinë
Për sa kohë që lidhja kryesore midis projektuesit dhe prototipit nuk është prishur, ne mund të vëzhgojmë foton e mëposhtme:

bëj_me= funksioni (_name) (
alarm ("Unë u lëshova");
ky .emri=_emri;
ky .show_name=funksion () (alarm(this .name);)
}

Make_me.prototype.set_name=funksion (_name) (ky .name=_name;)
fëmijë=new make_me("Vasya" );

Alert(lloji make_me.prototip); //objekt - funksioni ka një veti prototip
alert(lloji i fëmijës.prototip); //i papërcaktuar - objekti i krijuar NUK ka një veti prototip
alert(fëmijë.konstruktor.prototip === make_me.prototype); //true - por objekti ka një veti konstruktori, e cila tregon funksionin konstruktor make_me, i cili, nga ana tjetër, ka një veti prototip


* Ky kod burim u theksua me theksuesin e kodit burimor.

Siç e kam vënë re pasi lexova forume të shumta mbi këtë temë, problemi kryesor që njerëzit kanë është kur ata ngatërrojnë tiparin prototip të një funksioni me vetinë e fshehur [] të objektit të krijuar nga ai funksion.
Të dyja këto veti janë referencë për të njëjtin objekt (përderisa lidhja primare midis prototipit dhe konstruktorit nuk është prishur), por megjithatë ato janë veti të ndryshme, me emra të ndryshëm, njëri prej të cilëve është i aksesueshëm nga programuesi, dhe tjetri nuk është.

Gjithmonë është e nevojshme të kuptohet qartë se nëse po flasim për prototipin e konstruktorit, atëherë kjo është gjithmonë vetia e prototipit, dhe nëse po flasim për prototipin e objektit të krijuar, atëherë kjo është vetia e fshehur [].

Trashëgimia

Tani ne e dimë se çdo objekt ka një referencë prototipi të fshehur dhe çdo prototip është një objekt i rregullt.
Lexuesit më të ndjeshëm tashmë kanë kapur erën e rekursionit :)
Në të vërtetë, sepse një prototip është një objekt i zakonshëm, atëherë ai, nga ana tjetër, ka një lidhje me prototipin e tij, e kështu me radhë. Kështu zbatohet hierarkia e prototipit.
zog= funksioni () () //Ky është konstruktori i zogut
bird.prototype.cry=funksion ()(alarm("Qaj!");) //Zogu mund të bërtasë
bird.prototype.fly=funksion ()(alarm ("Unë jam duke fluturuar!");) //dhe fluturoj

Duck=funksion () ()
rosë.prototip=zog i ri();
duck.prototype.cry=function ()(alarm("Quack-quack!" ;) //Rosa bërtet ndryshe
rosë.prototip.konstruktor=rosë; //Cakto me forcë pronën prototype.constructor në duck, sepse përndryshe do t'i referohet zogut

Billy = rosë e re(); //Billy është rosa jonë
billy.fly(); //Une po fluturoj! - Billy mund të fluturojë sepse ai është një zog.
billy.cry(); //Kuak kuak! - Billy bërtet shaka, sepse ai është rosë.


* Ky kod burim u theksua me theksuesin e kodit burimor.

Në këtë mënyrë ju mund të zbatoni një hierarki të çdo niveli foleje.

Detyrë me yll

Tani, meqenëse dimë kaq shumë për të gjitha këto, le të përpiqemi të kuptojmë se sa shumë po ndodh në këto tre rreshta
bëj_me= funksioni () ()
fëmijë=new make_me();
alert(fëmijë.toString()); //daljet

* Ky kod burim u theksua me theksuesin e kodit burimor.

Në rreshtin e parë krijojmë një funksion të ri dhe një variabël të quajtur make_me që tregon atë funksion. Kjo krijon një prototip funksioni, make_me.prototype, i cili përmban një veti konstruktori që tregon make_me.
Por kjo nuk është e gjitha :)
Sepse funksioni make_me është gjithashtu një objekt, atëherë ai, nga ana tjetër, ka një baba dhe një nënë, d.m.th. projektuesi dhe prototipi. Konstruktori i tij është një funksion vendas i gjuhës Function(), dhe prototipi i tij është një objekt që përmban metodat call, application, etj. - Falë këtij prototipi ne mund t'i përdorim këto metoda në çdo funksion. Kështu, funksioni make_me ka një veçori [] që tregon Function.prototype.

Nga ana tjetër, prototipi i një konstruktori funksioni është gjithashtu një objekt, konstruktori i të cilit është (çudi!) Objekti (d.m.th. Funksioni.prototip.[].konstruktor===Objekt), dhe prototipi është një objekt që përmban vetitë standarde. dhe metodat e objektit, si toString, hasOwnProperty dhe të tjera (me fjalë të tjera - Function.prototype.[]["hasOwnProperty"] - kjo është pikërisht metoda që ne mund të përdorim në të gjitha objektet e prejardhura - dhe kjo është metoda e vet. të këtij objekti dhe jo të trashëguar). Në këtë mënyrë interesante zbulojmë se të gjitha llojet e objekteve rrjedhin nga Object.

A mund të vazhdojmë më tej? Rezulton se jo. Objekti.prototipi përmban vetitë themelore të objektit pikërisht sepse ai nuk ka prototipin e vet. Objekti.prototip.[]=null; Në këtë pikë, udhëtimi nëpër zinxhirin prototip në kërkim të një prone ose metodë ndalon.

Një tjetër fakt interesant është se konstruktori i Objektit është Funksioni. Ato. Objekti.[].konstruktor===Funksioni.
Ekziston një referencë tjetër rrethore - konstruktori i Object është Function, dhe konstruktori i Function.prototype është Object.

Le të kthehemi te shembulli ynë. Ne kemi kuptuar tashmë se si është krijuar funksioni, tani le të kalojmë në rreshtin e dytë. Aty krijojmë një objekt fëmijë, konstruktori i të cilit është funksioni make_me dhe prototipi i të cilit është make_me.prototype.

Epo, në rreshtin e tretë shohim se si përkthyesi shkon lart në zinxhir, nga fëmija në fëmijë.[] (aka make_me.prototype), pastaj te fëmija.[].[] (aka Object.prototype), dhe tashmë gjen atje. metodën toString, e cila nis ekzekutimin.

papastërtitë

Mund të duket se trashëgimia përmes prototipeve është e vetmja mënyrë e mundshme në JavaScript. Kjo eshte e gabuar.
Kemi të bëjmë me një gjuhë shumë fleksibël që ofron më shumë mundësi sesa rregulla.

Për shembull, nëse dëshirojmë, nuk mund të përdorim fare prototipe, por të programojmë duke përdorur konceptin e mixins. Për këtë do të na duhen miqtë tanë të mirë të vjetër - stilistë.

//Ky është një konstruktor njerëzor
njeri=funksion() (
this .live=function ()(alarm ("Unë jam drejtpërdrejt" ;) //Njeriu di të jetojë
this .walk=function ()(alarm ("Unë jam duke ecur" ;) //Njeriu mund të ecë
}

//Ky është konstruktori i poetit
poet=funksion ()(
ky .kill=funksion ()(alarm( "Poeti vrau një njeri");} //Një poet mund të vrasë një person
this .live=function ()(alarm("Kam vdekur" ;) //Një person do të vdesë nga kjo
}

Vladimir=njeri i ri(); //Vladimir është burrë
vladimir.live(); //Unë jetoj - ai është gjallë
vladimir.ec (); //Unë jam duke ecur - ai është duke ecur

Poet.thirrje(vlladimir); //Ekzekutoni konstruktorin poet për objektin vladimir
vladimir.kill(); //Poeti vrau një burrë
vladimir.live(); //Jam i vdekur

//Tani fokusohu
burrë.thirr (vlladimir);
vladimir.live(); //Une jetoj


* Ky kod burim u theksua me theksuesin e kodit burimor.

Çfarë shohim në këtë shembull? Së pari, është e mundur të trashëgohet nga disa objekte që nuk janë në të njëjtën hierarki. Në shembull ka 2 prej tyre, por mund të ketë sa të doni.
Së dyti, nuk ka fare hierarki. Mbështetja e vetive dhe metodave përcaktohet vetëm nga radha në të cilën thirren konstruktorët.
Së treti, kjo është aftësia për të ndryshuar një objekt edhe më dinamik, veçanërisht një objekt individual, dhe jo të gjithë pasardhësit e tij, si kur ndryshoni një prototip.

Përditësim: Mbylljet dhe pronat private

Për të mos e fryrë këtë artikull tashmë mjaft të madh, unë jap një lidhje me postimin Mbylljet në JavaScript, ku kjo është shkruar në disa detaje.

Çfarë të bëni tani me gjithë këtë

Siç thashë më lart, modifikimi arbitrar i objekteve individuale, përdorimi i konstruktorëve, mikseve dhe fleksibiliteti i prototipeve janë vetëm mjete, mundësi që i lejojnë programuesit të krijojë kode të tmerrshme dhe të mrekullueshme në të gjitha aspektet. Është e rëndësishme vetëm të kuptojmë se cilat probleme zgjidhim, me çfarë mjetesh, çfarë qëllimesh arrijmë dhe çfarë çmimi paguajmë për të.

Për më tepër, çështja e çmimit është mjaft jo e parëndësishme, veçanërisht nëse po flasim për zhvillimin e versioneve të shfletuesit Internet Explorer 6 dhe 7.
1. Kujtesa - gjithçka është e thjeshtë këtu. Në të gjithë shfletuesit, trashëgimia në prototipe merr shumë më pak memorie sesa kur krijohen metoda përmes konstruktorëve. Për më tepër, sa më shumë metoda dhe veti të kemi, aq më i madh është ndryshimi. Sidoqoftë, vlen të kujtojmë se nëse nuk kemi një mijë objekte identike, por vetëm një, atëherë konsumi i kujtesës në çdo rast do të jetë i vogël, sepse Ka faktorë të tjerë për t'u marrë parasysh këtu.
2. Koha e procesorit - këtu hollësitë kryesore lidhen posaçërisht me shfletuesit nga Microsoft.
Nga njëra anë, objektet ku metodat dhe vetitë krijohen përmes një konstruktori mund të krijohen shumë herë (në disa raste dhjetëra e qindra herë) më ngadalë sesa përmes një prototipi. Sa më shumë metoda, aq më i ngadalshëm është. Pra, nëse IE juaj ngrin për disa sekonda gjatë inicializimit të skriptit, ka një arsye për të gërmuar në këtë drejtim.

Nga ana tjetër, metodat e vetë një objekti (ato të krijuara përmes konstruktorit) mund të ekzekutohen pak më shpejt se metodat prototip. Nëse keni nevojë të dëshpëruar për të përshpejtuar ekzekutimin e një metode të veçantë në këtë shfletues, atëherë duhet ta merrni parasysh këtë. Mbani në mend se është thirrja e metodës (d.m.th., kërkimi i saj në objekt) që përshpejtohet, jo ekzekutimi i saj. Pra, nëse vetë metoda funksionon për një sekondë, atëherë nuk do të vini re shumë rritje të performancës.

Probleme të ngjashme vërehen në shfletues të tjerë, ku koha për krijimin e objekteve dhe thirrjen e metodave të tyre është afërsisht e njëjtë për të dy qasjet.

P.S. Zakonisht në artikuj të këtij lloji autori ofron një lloj mbështjellësi, ose duke u përpjekur të zbatojë trashëgiminë e objektit klasë bazuar në trashëgiminë prototipike, ose thjesht sheqer sintaksor për trashëgiminë prototipike. Unë nuk e bëj këtë qëllimisht, sepse ... Unë besoj se një person që e kupton kuptimin e këtij artikulli është në gjendje të shkruajë çdo mbështjellës për vete, dhe shumë gjëra të tjera interesante :)

Etiketa: Shtoni etiketa

JavaScript është një gjuhë e orientuar drejt objektit. Me përjashtim të konstrukteve bazë të gjuhës, të tilla si unazat dhe operatorët relacionalë, pothuajse çdo veçori e JavaScript zbatohet duke përdorur objekte në një mënyrë ose në një tjetër.

Ndonjëherë objektet përdoren në mënyrë eksplicite për të kryer detyra specifike, të tilla si përpunimi i dokumenteve (X)HTML dhe XML bazuar në Modelin e Objektit të Dokumentit. Në raste të tjera, roli i objekteve është më pak i dukshëm, siç është roli i objektit String kur punoni me të dhëna primitive të vargut.

Kapitujt e mëparshëm kanë dhënë shembuj që tregojnë qartë dobinë e objekteve të integruara, por në këtë kapitull ne do të zhytemi drejtpërdrejt në objektet JavaScript.

Objektet në JavaScript

Objektet në JavaScript mund të ndahen në katër grupe.

  1. Objektet e përdoruesit të krijuara nga programuesi dhe që kanë një strukturë dhe entitet që i përshtaten një detyre programimi specifike. Mundësitë e krijimit dhe përdorimit të objekteve të tilla do të diskutojmë në këtë kapitull.
  2. Objektet e integruara sigurohen nga vetë gjuha JavaScript. Këto përfshijnë objekte që lidhen me llojet e të dhënave (String, Number dhe Boolean), objekte që ju lejojnë të krijoni objekte të personalizuara dhe lloje të përbëra (Object dhe Array) dhe objekte që i bëjnë detyrat e zakonshme më të lehta (të tilla si Data, Math, dhe RegExp). Aftësitë e objekteve të integruara rregullohen nga standardi i gjuhës ECMA-262 dhe, në një masë më të vogël, nga specifikimet e prodhuesit të shfletuesit.
  3. Objektet e shfletuesit që nuk janë pjesë e gjuhës JavaScript por mbështeten nga shumica e shfletuesve. Shembuj të objekteve të shfletuesit janë Window, një objekt përmes të cilit dritaret e shfletuesit menaxhohen dhe ndërveprojnë me përdoruesin, dhe Navigator, një objekt që ofron informacione të konfigurimit të klientit. Për shkak se shumica e aspekteve të objekteve të shfletuesit nuk rregullohen nga asnjë standard, vetitë dhe sjellja e tyre mund të ndryshojnë shumë në varësi të shfletuesit dhe versionit të tij. Objektet e këtij lloji do të diskutohen më tej.
  4. Objektet e dokumentit janë pjesë e Modelit të Objektit të Dokumentit (DOM), i përcaktuar nga konsorciumi W3C. Objekte të tilla i ofrojnë programuesit një ndërfaqe të strukturuar për dokumentet (X)HTML dhe XML. Janë këto objekte që ofrojnë JavaScript me aftësinë për të manipuluar fletët e stilit të ndërthurur (CSS - Cascade Style Sheet) dhe thjeshtojnë zbatimin e HTML dinamike (DHTML). Qasja në objektet e dokumentit sigurohet nga shfletuesi përmes vetive të dokumentit të objektit Window (dritare. dokument). Do të flasim më shumë për DOM më vonë.

Parimet e punës me objekte

Nje objektështë një koleksion i parregulluar i të dhënave, duke përfshirë llojet primitive të të dhënave, funksionet dhe madje edhe objektet e tjera. Përfitimi i objekteve është se ato përqendrojnë në një vend të gjitha të dhënat dhe logjikën e nevojshme për të kryer një detyrë specifike. Objekti String ruan të dhënat e tekstit dhe ofron shumë nga funksionet e nevojshme për të vepruar në të. Megjithëse prania e objekteve në një gjuhë programimi nuk është aspak e nevojshme (nuk ka objekte në gjuhën C, për shembull), ato sigurisht që thjeshtojnë përdorimin e gjuhës.

Krijimi i objekteve

Një objekt krijohet duke përdorur një konstruktor - një lloj i veçantë funksioni që përgatit një objekt të ri për përdorim duke inicializuar memorien e zënë nga Objekti. Në kapitullin 4, pamë se objektet mund të krijohen duke aplikuar operatorin e ri te konstruktorët e tyre. Përdorimi i këtij operacioni bën që konstruktori të krijojë një objekt të ri, natyra e të cilit përcaktohet nga konstruktori që thirret. Për shembull, konstruktori String() krijon objekte String, dhe konstruktori Array() krijon objekte Array. Kështu emërtohen llojet e objekteve në JavaScript: me emrin e konstruktorit që krijon objektin.
Këtu është një shembull i thjeshtë i krijimit të një objekti:

var qytet = varg i ri();

Kjo deklaratë krijon një objekt të ri String dhe vendos një referencë për të në variablin qytet. Këtu, konstruktorit nuk i jepet asnjë argument, kështu që ndryshorja city do të marrë vlerën e saj të paracaktuar - në këtë rast, vargun bosh. Ju mund ta bëni këtë shembull më interesant duke i kaluar një argument konstruktorit që specifikon vlerën fillestare:

var qytet = varg i ri ("San Diego");

Artikujt më të mirë mbi këtë temë