MySQL Java JavaScript PHP Python HTML-CSS C-sharp

Programarea orientată pe obiecte (OOP)

Programarea orientată pe obiect (OOP) în prezent reprezintă una dintre paradigmele dominante în dezvoltarea aplicațiilor, iar în JavaScript putem beneficia de toate avantajele OOP. În același timp, programarea orientată pe obiect în JavaScript are unele particularități.

Obiecte

În temele anterioare am lucrat cu date primitive - numere, șiruri de caractere, însă datele nu sunt întotdeauna reprezentate de tipuri primitive. De exemplu, dacă în programul nostru trebuie să descriem o entitate de tip om, care are nume, vârstă, sex și altele, evident că nu vom putea reprezenta entitatea om ca un număr sau un șir de caractere.

Vom avea nevoie de mai multe șiruri sau numere pentru a descrie în mod corespunzător o persoană. În acest sens, omul va funcționa ca o structură complexă, având proprietăți separate - vârstă, înălțime, nume, prenume etc.

Pentru a lucra cu astfel de structuri în JavaScript, se utilizează obiectele. Fiecare obiect poate să stocheze proprietăți care descriu starea sa și metode care descriu comportamentul său.

Crearea unui obiect nou

Există mai multe moduri de a crea un obiect nou

Primul mod implică utilizarea constructorului Object:

const user = new Object();

În acest caz, obiectul este denumit user.

Expresia new Object() reprezintă apelul constructorului - funcției care creează un obiect nou. Pentru a apela constructorul, se utilizează operatorul new. Apelul constructorului seamănă în mod efectiv cu apelul unei funcții obișnuite.

Al doilea mod de a crea un obiect implică utilizarea acoladelor (notația literală):

const user = {};
user.name = "Tom";
user.age = 26;

În acest caz, sunt declarate două proprietăți, name și age, cărora li se atribuie valorile corespunzătoare. După aceasta, putem utiliza aceste proprietăți, de exemplu, pentru a afișa valorile lor în consolă:

console.log(user.name);
console.log(user.age);

De asemenea, poți defini proprietățile în timpul definirii obiectului:

const user = {
 
   name: "Tom",
   age: 26
};

În acest caz, pentru a atribui o valoare proprietății se folosește simbolul dublu punct, iar după definirea proprietății se pune o virgulă (nu punct și virgulă).

În plus, este disponibilă o modalitate prescurtată de definire a proprietăților:

const name = "Tom";
const age = 34;
const user = {name, age};
console.log(user.name);     // Tom
console.log(user.age);      // 34

În acest caz, denumirile variabilelor sunt și denumirile proprietăților obiectului. Astfel, poți crea construcții mai complexe:

const name = "Tom";
const age = 34;
const user = {name, age};

const teacher = {user, course: "JavaScript"};
console.log(teacher.user);      // {name: "Tom", age: 34}
console.log(teacher.course);    // JavaScript

Metodele obiectului

Metodele unui obiect definesc comportamentul sau acțiunile pe care le efectuează. Metodele sunt, în esență, funcții. De exemplu, să definim o metodă care să afișeze numele și vârsta unei persoane:

const user = {};
user.name = "Tom";
user.age = 26;
user.display = function(){
   
   console.log(user.name);
   console.log(user.age);
};

// chemarea metodei
user.display();

La fel ca în cazul funcțiilor, metodele sunt mai întâi definite și apoi apelate.

De asemenea, metodele pot fi definite direct la momentul definirii obiectului:

const user = {
 
   name: "Tom",
   age: 26,
   display: function(){
     
       console.log(this.name);
       console.log(this.age);
   }
};

La fel ca și în cazul proprietăților, unei metode i se atribuie o referință la o funcție folosind dublul punct.

Pentru a accesa proprietățile sau metodele unui obiect în cadrul acelui obiect, se folosește cuvântul cheie `this`. Acesta indică o referință la obiectul curent.

De asemenea, se poate utiliza o modalitate prescurtată de definire a metodelor, când se omit dublul punct și cuvântul cheie `function`:

let user = {
 
   name: "Tom",
   age: 26,
   display(){
     
       console.log(this.name, this.age);
   },
   move(place){
       console.log(this.name, "goes to", place);
   }
};
user.display(); // Tom 26
user.move("the shop");  // Tom goes to the shop

Sintaxa pentru Matrice

Există și o modalitate alternativă de a defini proprietăți și metode folosind sintaxa matriceală:

const user = {};
user["name"] = "Tom";
user["age"] = 26;
user["display"] = function(){
   
   console.log(user.name);
   console.log(user.age);
};

// chemarea metodei
user["display"]();

Numirea fiecărei proprietăți sau metode este plasată între ghilimele și în paranteze pătrate, apoi i se atribuie o valoare. De exemplu, user["age"] = 26.

Atunci când se accesează aceste proprietăți și metode, puteți utiliza fie notația cu punct (user.name), fie accesați astfel: user["name"]

De asemenea, puteți defini proprietăți și metode folosind direct sintaxa matriceală în momentul creării obiectului:

const user = {
   ["name"]: "Tom",
   ["age"]: 26,
   ["display"]: function(){
     
       console.log(user.name);
       console.log(user.age);
   }
};
user["display"]();

Șirurile ca proprietăți și metode

De asemenea, trebuie de menționat că numele proprietăților și metodelor unui obiect sunt întotdeauna reprezentate de șiruri. Cu alte cuvinte, putem rescrie definiția anterioară a obiectului astfel:

const user = {
   "name": "Tom",
   "age": 26,
   "display": function(){
   
       console.log(user.name);
       console.log(user.age);
   }
};
// chemarea metodei
user.display();

Pe de o parte, nu există nicio diferență între cele două definiții. Pe de altă parte, există situații în care închiderea numelui într-un șir poate fi de ajutor. De exemplu, dacă numele proprietății constă în două cuvinte separate de un spațiu:

const user = {
   name: "Tom",
   age: 26,
   "full name": "Tom Johns",
   "display info": function(){
   
       console.log(user.name);
       console.log(user.age);
   }
};
console.log(user["full name"]);
user["display info"]();

În acest caz, pentru a accesa astfel de proprietăți și metode, trebuie să utilizăm sintaxa de tablou.

Sintaxa tabloului ne oferă o altă opțiune - definirea numelui proprietății în afara obiectului:

const prop1  = "name";
const prop2  = "age";
const tom = {
   [prop1]: "Tom",
   [prop2]: 37
};
console.log(tom);           // {name: "Tom", age: 37}
console.log(tom.name);      // Tom
console.log(tom["age"]);    // 37

Datorită acestui fapt, de exemplu, se pot crea dinamic obiecte cu nume de proprietăți arbitrare:

function createObject(propName, propValue){
   return {
           [propName]: propValue,
           print(){
               console.log(`${propName}: ${propValue}`);
           }
   };
}
const person = createObject("name", "Tom");
person.print();     // name: Tom

const book = createObject("title", "JavaScript Reference");
book.print();   // title: JavaScript Reference

Ștergerea proprietăților

Mai sus am văzut cum putem adăuga dinamic noi proprietăți la un obiect. Cu toate acestea, putem șterge, de asemenea, proprietăți și metode folosind operatorul delete. Și, la fel ca în cazul adăugării, putem șterge proprietățile în două moduri. Primul mod - utilizarea notației cu punct:

delete obiect.proprietate

Sau utilizarea sintaxei cu paranteze pătrate:

delete obiect["proprietate"]

De exemplu, vom șterge o proprietate:

let user = {};
user.name = "Tom";
user.age = 26;
user.display = function(){
   
   console.log(user.name);
   console.log(user.age);
};

console.log(user.name); // Tom
delete user.name; // ștergem proprietatea
// variantă alternativă
// delete user["name"];
console.log(user.name); // undefined

După ștergere, proprietatea nu va mai fi definită, astfel încât, la încercarea de accesare, programul va returna valoarea undefined.

Crearea unui obiect din variabile și constante

La crearea unui obiect, valorile variabilelor, constantelor sau rezultatele funcțiilor calculate dinamic pot fi transmise proprietăților sale:

function getSalary(status){
   if(status==="senior") return 1500;
   else return 500;
}
const name = "Tom";
const age = 37;
const person = { name: name, age: age, salary: getSalary()};

console.log(person);    // {name: "Tom", age: 37, salary: 500}

Dar dacă numele constantelor/variabilelor coincid cu numele proprietăților, putem simplifica transmiterea valorilor:

const name = "Tom";
const age = 37;
const salary = 500;
const person = { name, age, salary};

console.log(person);    // {name: "Tom", age: 37, salary: 500}

În acest caz, obiectul person va primi automat proprietățile, ale căror nume vor corespunde numelor constanelor, și ca valori vor avea valorile acestor constante.

Același lucru se aplică și atunci când se transmit funcții ca metode ale obiectului:

function display(){
   console.log(this.name, this.age);
}
const move = function(place){ console.log(this.name, "goes to", place)};
const name = "Tom";
const age = 37;
const salary = 500;
const person = { name, age, salary, display, move};

person.display();       // Tom 37
person.move("cinema");  // Tom goes to cinem

În acest caz, obiectul person are două metode care corespund funcțiilor transmise în obiect - display() și move(). Este important să menționăm că atunci când se transmit funcții ca metode ale obiectului, putem continua să utilizăm cuvântul cheie this în aceste funcții pentru a accesa funcționalitatea obiectului. Cu toate acestea, trebuie să fim atenți atunci când transmitem expresii lambda, deoarece pentru expresiile lambda globale, this va reprezenta obiectul fereastră al browserului:

const move = (place)=>{ console.log(this.name, "goes to", place); console.log(this);};
const name = "Tom";

const person = { name, move};
person.move("cinema");  //  goes to cinema

Funcția Object.fromEntries()

Cu ajutorul funcției Object.fromEntries() poți crea un obiect dintr-un set de perechi cheie-valoare, unde cheia va reprezenta numele proprietății. De exemplu, să creăm un obiect din array-uri:

const personData = [ ["name", "Tom"], ["age", 37]];
const person = Object.fromEntries(personData);
console.log(person);        // {name: "Tom", age: 37}
console.log(person.name);    // Tom

În acest caz, obiectul este creat din array-ul `personData`, care conține două sub-array-uri. Fiecare sub-array conține două elemente și reprezintă efectiv o pereche cheie-valoare. Primul element reprezintă cheia, iar al doilea - valoarea.

← Lecția anterioară Lecția următoare →