Programimi i orientuar nga objekti në Javascript

Të gjithëve u pëlqen programimi i orientuar drejt objekteve (OOP). Fshehni detajet e zbatimit për të ulur kompleksitetin? Më pak rishkrim i kodit? Më shumë projekte të mirëmbajtura? Me llogarit dhe mua! Javascript nuk është rruga më e drejtpërdrejtë për të mësuar se si të shkruani programe të orientuara nga objekti. Fillova të mësoj konceptet e programimit në Swift; shtypja statike dhe sintaksa e drejtpërdrejtë i bënë konceptet më komplekse OO shumë më të lehta për t'u kuptuar. Pra, kur unë, thjesht një fillestar, u futa në Javascript të orientuar drejt objekteve, isha si:

Ishte dukshëm e ndryshme nga çdo gjuhë tjetër që kisha parë deri në atë pikë. Gjithashtu, ka shumë JS të shkruara shumë keq atje, dhe shumë rregullime të shpejta nga Stack Overflow mund t'ju kafshojnë në bythë në projekte komplekse. Kështu që vendosa të shkruaj këtë postim me shpresën për të shpëtuar të tjerët nga i njëjti konfuzion që përjetova unë. Shënim për lexuesin: ky artikull supozon se ju i dini bazat e programimit të orientuar drejt objektit. Nëse nuk dini asgjë rreth programimit të orientuar drejt objektit ose përfitimeve të tij, lexoni fillimisht këtë artikull!

Ndërtimi i objekteve

Ka një sasi befasuese mënyrash se si mund të krijoni objekte në JS. Kjo është një nga gjërat që ngatërron shumë në fillim. Do të kaloj nëpër metodat bazë të krijimit të objekteve dhe do të diskutoj të mirat dhe të këqijat e secilit.

  • Literalet e objekteve

Fjalë për fjalë objekt i vjetër i mirë. Nuk ka sintaksë të çuditshme këtu:

var objectLiteralPerson = {
 // setting property
 name: "Bob Benson" ,
 // declare function
 greet () {
    
     // 'this' refers to current object 
     console.log("Hello, I'm " + this.name); 
}
}

Përparësitë e përdorimit të literaleve të objekteve për të krijuar objekte përfshijnë komoditetin, fleksibilitetin në deklarim dhe më pak kod gjatë deklarimit. Mund ta lëshoni një objekt fjalë për fjalë kudo në programin tuaj pa asnjë konfigurim të mëparshëm dhe do të funksionojë, gjë që mund të jetë shumë e dobishme! Megjithatë, ka padyshim probleme me fjalë për fjalë. Nëse dëshironi të krijoni dy objekte të ngjashme, duhet të kopjoni dhe ngjitni metodat dhe vetitë dhe të redaktoni atë që ju nevojitet të ndryshuar. Kjo kopjon sasinë e memories së përdorur dhe madhësinë e programit tuaj - kjo nuk është ideale për përdorimin ose mirëmbajtjen e memories. Përdorimi më i mirë i literaleve të objekteve është krijimi i një grupi unik të funksioneve dhe veçorive të lidhura që nuk do të ripërdoren në një mënyrë të ngjashme askund tjetër në programin tuaj.

  • Funksionet e fabrikës

Funksionet e fabrikës janë një mënyrë e mirë për të grupuar në mënyrë më efektive vetitë dhe funksionalitetin në objekte. Ato në thelb janë vetëm funksione që kthejnë një objekt. Kontrolloje:

function createPerson(name){
   return {
    name: name,
    greet: function() {console.log("Hello, I'm" + this.name);}
  }
}
var person = createPerson("Jack Johnson");

Këtu, createPerson(name)kthehet fjalë për fjalë një objekt që tani mund të përdoret si një objekt normal. Kjo metodë e krijimit të objekteve ia kalon duke përdorur fjalë për fjalë të objekteve të papërpunuara, sepse nuk keni nevojë të kopjoni dhe ngjitni të gjitha funksionet dhe vetitë e një objekti sa herë që dëshironi të deklaroni një shembull të ri të tij. Ju mund të kaloni parametra për të modifikuar lehtësisht objektet që dëshironi të ripërdorni me veti të ndryshme. Funksionet e fabrikës sigurojnë një element të ripërdorimit duke ruajtur shumë fleksibilitet që merrni me fjalë për fjalë të objekteve.

  • Funksionet e konstruktorit

Këto funksione janë mënyra më konvencionale për të krijuar objekte që përdorin funksionalitet nga njëri-tjetri duke përdorur trashëgiminë prototipale. Çfarë është trashëgimia prototipale, ju pyesni? Më lejoni t'ju tregoj duke përdorur funksionet e konstruktorit. Merrni objektin Person nga dy shembujt e fundit:

function Person(name) {
    // 1    
    this.name = name;
    this.greet = function() {
        console.log("Hello, I'm " + this.name);
    }
}
//2
var person = new Person("Jack Johnson");

//3
console.log(Object.getPrototypeOf(person)); // Person {}

Ja ku bëhet interesante. Unë do të eci nëpër hapat për të shpjeguar saktësisht se çfarë ndodh me fjalët kyçe new dhe this.

  1. this i referohet objektit aktualisht brenda fushës së funksionit Person. Ai vendos vetinë e tij name si vlerën e parametrit të kaluar në funksion.
  2. Një objekt i ri person krijohet duke përdorur funksionin konstruktor. Kur përdorni new, ai lidh një objekt të sapokrijuar me fjalën kyçe this brenda funksionit të thirrur konstruktor. Kjo lidhje lejon objektin person të referojë të gjithë funksionalitetin nga brenda funksionit të konstruktorit.
  3. Objekti që sapo krijuam ka një veti të quajtur prototype, dhe vlera është vetëm shablloni i objektit Person! Pra, kur thërrisni një funksion si greet() nga objekti person, shfletuesi kontrollon objektin person për funksionin. Nëse nuk është në atë objekt, shfletuesi kontrollon nëse është deklaruar brenda objektit prototype që është një veti e objektit person. Ai shkon lart në "zinxhirin" e objekteve dhe vetitë e tyre prototip derisa ose të gjejë funksionin ose të mos e gjejë atë, që do të thotë se funksioni është i papërcaktuar. Prona prototip është vendi ku përcaktohen anëtarët e trashëguar.

E di që kjo mund të jetë super konfuze. Nëse keni ndonjë pyetje ose dëshironi të keni qartësi se si funksionojnë saktësisht prototipet, ju lutem më dërgoni një mesazh ose koment dhe shikoni "dokumentet në Mozilla". Ju duhet ta mendoni atë pasi funksionaliteti i objektit po delegohet prototip, në vend që të kopjohet nga superklasa.

Pra, pse më duhet të përdor funksionet e konstruktorit? Pse nuk mund t'i përmbahem funksioneve të fabrikës? Epo, një koncept i OOP është të shkruani kod të ripërdorshëm dhe lehtësisht të zgjatshëm. Funksionet e konstruktorit na lejojnë ta bëjmë këtë duke vepruar si prototip/shabllon për objekte të tjera, duke i dhënë funksionalitetin dhe vetitë e tyre objektit duke e përdorur atë si prototip. Po sikur të dua të bëj një version të zgjeruar të Person? Po për një Athlete? Ja se si do ta bëja:

function Athlete(name,sport) {
    // 1
    Person.call(this,name);
    this.sport = sport;
}
// Tip: declare your properties inside the constructor functions and methods on the prototype property, outside of the constructor.
Athlete.prototype.play = function() {
    console.log(this.name + " is playing " + this.sport);
}
// 2
Athlete.prototype = Object.create(Person.prototype);
// 3 
Athlete.prototype.constructor = Athlete;
var athlete = new Athlete("Serena Williams","Tennis");

athlete.greet(); // Hello, I'm Serena Williams

Këtu janë hapat për të zbatuar trashëgiminë prototipale me folje minimale:

  1. Ju e kaloni objektin aktual përmes funksionit konstruktor Person për të fituar funksionalitetin e tij. Pastaj vendosni veçorinë sport që është e disponueshme vetëm për objektet Athlete.

2. Vendosni prototipin e funksionit të konstruktorit në një objekt të ri të krijuar nga prototipi i objektit që dëshironi të trashëgoni (në këtë rast personi)

3. Faleminderit Greg Pawlowski që e theksoi këtë — mos harroni të vendosni funksionin e konstruktorit në mënyrë të përshtatshme për qartësi se cili funksion konstruktor është përgjegjës për krijimin e objektit.

Përditësim dinamik

Hapat 2 dhe 3 në shembullin e mëparshëm më lejuan të konfiguroja përditësimin dinamik në të gjithë zinxhirin e prototipit. Kjo do të thotë që unë mund të deklaroj një funksion ose pronë në prototipin e një funksioni konstruktor pasi të deklaroj një shembull, dhe shembulli përditësohet me atë pronë ose funksion. Ajo funksionon si kjo:

// Assume that the Athlete and Person constructor function are already defined above
var athlete = new Athlete("MJ","Basketball")
// I can declare a new method on the Athlete prototype and the instance I just created will update 
Athlete.prototype.play = function() {
   console.log("Playing " + this.sport);
}
athlete.play(): // Playing Basketball

Ajo që është vërtet interesante është se unë mund të përditësoj në mënyrë dinamike instancat Athlete duke shtuar në prototipin Person:

Person.prototype.walk = function() {
    console.log(this.name + " is walking");
}
athlete.walk(); // MJ is walking

Vendosja e këtij përditësimi dinamik në të gjithë zinxhirin e prototipit ju jep shumë fleksibilitet në zgjerimin e objekteve dhe përdorimin e trashëgimisë për aftësitë maksimale të tij. Mbani mend, për ta zbatuar këtë ju duhet të vendosni vetitë e prototipit siç bëra në shembullin e mëparshëm.

Këto janë tre mënyra themelore për të krijuar objekte duke përdorur Javascript! Megjithëse i kalova këto tre mënyra, ka kaq shumë (është disi qesharake, në fakt) mënyra për të deklaruar objektet në Javascript. Nëse dëshironi të dini më shumë rreth modeleve të ndryshme të instancimit, shikoni këtë artikull nga pika e sajtit dhe këtë nga John Dugan.

  • Klasat ES6

Një diskutim i OO në JS nuk do të ishte i plotë pa prekur "Klasat ES6"! Ky është një hap i madh për gjuhën dhe mund të çojë në adoptim edhe më të gjerë të Javascript. Klasat ES6 do t'ju kujtojnë të deklaroni një klasë në gjuhë më konvencionale OO. Ja si e bëni:

class Person {
    constructor(name){
        this.name = name;
    }
   greet() {
    console.log("Hello, I'm " + this.name);
    }
}

// To implement inheritance 
class Athlete extends Person {
   
 // You have to call super() before you invoke "this"
    constructor(name,sport) {
        super(name)
        this.sport = sport
    }
}

Vë bast se jeni të sëmurë dhe të lodhur duke lexuar përpjekjet e mia ngatërruese për të shpjeguar se çfarë po ndodh nën kapuç, kështu që shikoni "këtë artikull" për më shumë informacion se si të përdorni klasat ES6 në mënyrë optimale.

Tani, e di që mund të jetë shumë joshëse të dilni dhe të përdorni njohuritë tuaja të reja të trashëgimisë prototipale dhe koncepteve të tjera të OO në Javascript, por mbani mend se është një mjet që duhet ta keni në brez, jo një plumb argjendi. Me shumë mundësi nuk do të dëshironi të përdorni trashëgiminë në projekte më të vogla, sepse kompleksiteti i shtuar nuk ia vlen përfitimet.

Situatat më të mira për të përdorur klasat dhe funksionet e konstruktorit qëndrojnë në programe më të mëdha, komplekse ku keni nevojë për kod të organizuar, të mirëmbajtur dhe të thjeshtë. Përdorimi i fuqisë së trashëgimisë mund të bëjë një ndryshim të madh në bazat e kodeve të mijëra rreshtave, sepse ju detyron të kategorizoni funksionalitetin, të organizoni komponentët e ndryshëm të sistemit tuaj dhe të modularizoni kodin tuaj në objekte të mirëpërcaktuara.

Faleminderit per leximin! Nëse do t'ju ndihmonte fare, disa duartrokitje do të vlerësoheshin shumë :) Gjithashtu, ju kërkoj falje për kodin e formatuar dobët… A di ndokush se si ta zgjidhë këtë problem? Sepse formatimi i kodit në medium është ndoshta pengesa e vetme më e madhe për mua në krijimin e postimeve në blog. Faleminderit paraprakisht.

✉️ Abonohu ​​nëCodeBurstnjë herë në javë Email Blast,🐦 NdiqCodeBurstTwitter, shikoni ».