MySQL Java JavaScript PHP Python HTML-CSS C-sharp

Proprietăți și metode de acces

Pentru a intermedi accesul la proprietățile unei clase, în ultimele standarde JavaScript a fost adăugat suport pentru metodele de acces - get și set. Mai întâi, să examinăm problema cu care ne putem confrunta:

class Person{
   constructor(name, age){
       this.name = name;
       this.age = age;
   }
}
const tom = new Person("Tom", 37);
console.log(tom.age);   // 37
tom.age = -15;
console.log(tom.age);   // -15

Clasa Person definește două proprietăți - name (nume) și age (vârstă a persoanei), ale căror valori le putem obține sau seta. Dar ce se întâmplă dacă transmitem valori incorecte? De exemplu, în exemplul de mai sus, proprietății age i se transmite un număr negativ, însă vârsta nu poate fi negativă.

Pentru a ieși din această situație, putem defini un câmp privat age, la care am putea avea acces doar din interiorul clasei curente. Și pentru a obține sau seta valoarea sa, putem crea metode speciale:

class Person{
   #ageValue = 1;
   constructor(name, age){
       this.name = name;
       this.setAge(age);
   }
   getAge(){
       return this.#ageValue;
   }
   setAge(value){ if(value>0 && value < 110) this.#ageValue = value; }
}
const tom = new Person("Tom", 37);
console.log(tom.getAge());  // 37
tom.setAge(-15);
console.log(tom.getAge());  // 37

Acum vârsta este stocată în câmpul privat ageValue. La setarea sa în metoda setAge(), se verifică valoarea furnizată. Setarea are loc doar dacă valoarea furnizată este corectă. Metoda getAge() returnează valoarea acestei variabile.

Dar există și o altă soluție - utilizarea metodelor de acces get și set.

// Definirea unui câmp privat
#field;
set field(value){
   this.#field= value;
}
get field(){
   return this.#field;
}

Ambele metode - get și set - au aceleași nume. De obicei, ele intermedierează accesul la un anumit câmp privat. Metoda set este destinată pentru setare și primește noul valor ca parametru. Ulterior, în metoda set, putem efectua o serie de acțiuni la momentul setării.

Metoda get este destinată pentru obținere și returnează valoarea. Aici, putem defini o logică pentru returnarea valorii.

Astfel, vom rescrie exemplul anterior folosind get și set:

class Person{
   #ageValue = 1;
   constructor(name, age){
       this.name = name;
       this.age = age;
   }
   set age(value){
       console.log(`Transmis ${value}`);
       if(value>0 && value < 110) this.#ageValue = value;
   }
   get age(){
       return this.#ageValue;
   }
}
const tom = new Person("Tom", 37);
console.log(tom.age);
tom.age = -15;
console.log(tom.age);

Este bine de menționat că lucrul cu metodele de acces se face în același mod ca și cu proprietățile obișnuite. Astfel, pentru a obține valoarea și a o afișa în consolă, se folosește un apel:

console.log(tom.age);

Dar nu

console.log(tom.age());

La accesarea `tom.age`, efectiv se va apela metoda `get`, care va returna valoarea câmpului `ageValue`.

Iar la apelul

tom.age = -15;

Efectiv, se va declanșa metoda `set`, care va primi valoarea transmisă prin singurul său parametru (în acest caz, numărul -15). Mai departe, în cadrul metodei `set`, putem decide dacă să setăm această valoare sau nu.

Proprietăți disponibile doar pentru citire

Anterior, am folosit ambele metode `get` și `set`, prin urmare, valoarea câmpului putea fi atât obținută, cât și setată. Cu toate acestea, în practică, putem folosi doar una dintre ele. De exemplu, putem menține doar metoda `get`, făcând astfel proprietatea disponibilă doar pentru citire.

De exemplu, vom modifica exemplul anterior și vom face proprietatea `name` disponibilă doar pentru citire:

class Person {
   #age = 1;
   #name;
   
   constructor(name, age) {
       this.#name = name;
       this.age = age;
   }

   //set name(value){ this.#name = value; }
   get name() { return this.#name; }
   
   set age(value) { if (value > 0 && value < 110) this.#age = value; }
   get age() { return this.#age; }
}

const tom = new Person("Tom", 37);
console.log(tom.name);  // Tom
tom.name = "Bob";       // Aceasta nu va schimba nimic
console.log(tom.name);  // Tom - valoarea nu s-a modificat

În acest caz, în loc de o proprietate publică `name`, este definit un câmp privat `#name`. Acesta poate fi setat doar din interiorul clasei, ceea ce facem în constructorul clasei. Cu toate acestea, din exterior, acesta poate fi doar citit folosind metoda `get`. Prin urmare, încercarea de a seta proprietatea `name` din exterior, așa cum este evidențiat în comentariu:

tom.name = "Bob";

Nu va avea niciun efect.

Proprietăți doar pentru setare

De asemenea, putem face o proprietate disponibilă doar pentru scriere, lăsând doar metoda set. De exemplu, să adăugăm o nouă proprietate "id", care va fi disponibilă doar pentru scriere:

class Person {
   #id;
   constructor(name, age, id) {
       this.name = name;
       this.age = age;
       this.id = id;
   }
   set id(value) { this.#id = value; }
   print() {
       console.log(`id: ${this.#id}   name: ${this.name}   age: ${this.age}`);
   }
}

const tom = new Person("Tom", 37, 1);
tom.print();            // id: 1   name: Tom   age: 37
tom.id = 55;            // setăm valoarea proprietății id
tom.print();            // id: 55   name: Tom   age: 37
console.log(tom.id);    // undefined - nu se poate obține valoarea proprietății id

În acest cod este definită proprietatea `id`, care setează valoarea câmpului privat `#id`. Deoarece nu este definită metoda `get` pentru această proprietate, la încercarea de a obține valoarea proprietății `id`, se va obține `undefined`:

console.log(tom.id);    // undefined - nu se poate obține valoarea proprietății id

Proprietăți fără referire la câmpuri

Trebuie menționat că metodele get și set nu sunt obligate să facă referire la câmpuri private sau necompletate. Acestea pot fi și proprietăți calculate. De exemplu:

class Person{
   constructor(firstName, lastName){
       this.firstName = firstName;
       this.lastName = lastName;
   }
   get fullName(){ return `${this.firstName} ${this.lastName}` }
}
const tom = new Person("Tom", "Smith");
console.log(tom.fullName);  // Tom Smith

În acest caz, proprietatea de citire `fullName` returnează, de fapt, concatenarea a două proprietăți - `firstName` și `lastName`.

În mod similar, se poate defini o proprietate pentru scriere:

class Person{
   constructor(firstName, lastName){
       this.firstName = firstName;
       this.lastName = lastName;
   }
   get fullName(){ return `${this.firstName} ${this.lastName}` }
   set fullName(value){
       [this.firstName, this.lastName] = value.split(" ");
   }
}
const tom = new Person("Tom", "Smith");
console.log(tom.fullName);  // Tom Smith
tom.fullName = "Tomas Jefferson";
console.log(tom.lastName);  // Jefferson

În acest caz, metoda set a proprietății `fullName` primește un anumit șir și, folosind metoda `split`, îl împarte în funcție de spațiu pentru a obține un șir de substraturi separate prin spațiu. Astfel, teoretic, ne așteptăm să fie furnizat ceva similar cu "Tom Smith", iar după despărțirea la spațiu, proprietatea `firstName` va primi valoarea "Tom", iar `lastName` va primi valoarea "Smith".

Trebuie menționat că, în scopul simplității și pentru a evidenția demonstrația, nu tratăm situațiile excepționale, cum ar fi furnizarea unui șir gol sau a unui șir care nu poate fi împărțit în două părți în funcție de spațiu, etc.

În final, la obținerea unei noi valori:

tom.fullName = "Tomas Jefferson";

Metoda set îl va diviza prin spațiu, iar primul element al array-ului va fi atribuit proprietății firstName, în timp ce al doilea element va fi atribuit proprietății lastName.

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