MySQL Java JavaScript PHP Python HTML-CSS C-sharp

Obiecte în funcții

Obiect ca rezultat al unei funcții

Funcțiile pot returna obiecte. Acest lucru poate fi util în diverse situații. Să luăm, de exemplu, crearea unui obiect și să o plasăm într-o funcție separată:

function createUser(pName, pAge) {
   return {
       name: pName,
       age: pAge,
       print: function() {
           console.log(`Nume: ${this.name}  Vârstă: ${this.age}`);
       }
   };
};
const tom = createUser("Tom", 26);
tom.print();
const alice = createUser("Alice", 24);
alice.print();

În acest caz, funcția createUser() primește valorile pName și pAge și creează un nou obiect pe baza acestora, care este rezultatul returnat. Rezultatul programului este:

Nume: Tom  Vârstă: 26
Nume: Alice  Vârstă: 24

Avantajul externalizării creării obiectului într-o funcție constă în faptul că ulterior putem crea mai multe obiecte similare cu valori diferite, adică să funcționăm ca o fabrică sau un constructor. În plus, într-o astfel de funcție putem verifica valorile furnizate pentru corectitudine și, în cazul în care sunt incorecte, putem reacționa în consecință.

function createUser(pName, pAge) {
 if (pAge < 1 || pAge > 110) {       // dacă vârsta este mai mică de 1 sau mai mare de 110
   console.log("Vârsta nu este validă");
   pAge = 1;
 }
 return {
   name: pName,
   age: pAge,
   print: function () {
     console.log(`Nume: ${this.name}  Vârstă: ${this.age}`);
   },
 };
}

const tom = createUser("Tom", 26);
tom.print();
const alice = createUser("Alice", 12345);
alice.print();

Aici se verifică parametrul pAge, care reprezintă vârsta utilizatorului. În mod teoretic, acesta poate fi orice număr, inclusiv unul care depășește limitele rezonabile, de exemplu, să fie negativ. În acest caz, verificăm dacă pAge corespunde acestor limite. Dacă valoarea pAge nu corespunde limitei, îi atribuim o valoare implicită - în acest caz, 1, și afișăm un mesaj diagnostic în consolă. Output-ul programului:

Nume: Tom  Vârstă: 26
Vârsta nu este validă
Nume: Alice  Vârstă: 1

Returnarea unui obiect poate fi utilă atunci când trebuie să întoarcem dintr-o funcție mai mult de un rezultat - în acest caz, le putem uni într-un singur obiect. De exemplu, o funcție primește un șir și găsește valorile minime și maxime în el:

function getMinMax(numbers){

 // dacă șirul este gol, valorile minime și maxime nu sunt definite
 if(numbers.length === 0) return {min: undefined, max: undefined};

 let minNumber = numbers[0];
 let maxNumber = numbers[0];
 for(let i=1; i< numbers.length; i++){
   
   if(minNumber > numbers[i]) minNumber = numbers[i];
   if(maxNumber < numbers[i]) maxNumber = numbers[i];
 }
 return {min: minNumber, max: maxNumber};
}

const nums = [1, 2, 3, 4, 5];
const result = getMinMax(nums);
console.log("Min:", result.min);    // Min: 1
console.log("Max:", result.max);    // Max: 5

Aici, în funcția getMinMax, primim un șir. Dacă șirul nu conține numere, returnăm un obiect în care câmpurile min și max au valori nedefinite. În caz contrar, parcurgem întregul șir și calculăm valorile maxime și minime, întorcându-le sub forma unui singur obiect.

Obiectul ca parametru

La fel ca și celelalte valori, un obiect poate fi transmis ca parametru către o funcție.

function printPerson(person){

 console.log("Name:", person.name);
 console.log("Age:", person.age);
}

const tom = {name: "Tom", age: 39};
const alice = {name: "Alice", age: 35};

printPerson(tom);
printPerson(alice);

În acest exemplu, funcția printPerson primește un obiect, presupunând că acesta are două proprietăți: name și age.

Trebuie să reținem că obiectele sunt tipuri de date referențiale, iar variabila/constantă/parametrul care reprezintă obiectul stochează de fapt o referință către obiect în memorie, nu obiectul în sine. Prin urmare, atunci când un obiect este transmis ca argument către o funcție, se transmite o copie a referinței către acel obiect. Și prin intermediul acestei referințe, funcția poate modifica diverse proprietăți ale obiectului.

function setAge(person, pAge){

 person.age = pAge;
}

const sam = {name: "Sam", age: 29};
console.log("Before setAge:", sam.age);
setAge(sam, 30);
console.log("After setAge:", sam.age);

Aici, mai întâi definim constanta sam, care reprezintă un obiect cu proprietățile name și age:

const sam = {name: "Sam", age: 29};

De fapt, constanta sam stochează o referință la zona de memorie în care este plasat obiectul.

Apelăm apoi funcția setAge, care primește obiectul person și îi schimbă proprietatea age.

setAge(sam, 30);

Deoarece obiectele sunt transmise prin referință, funcția setAge primește o copie a referinței stocate în constanta sam. Prin urmare, după aceasta, constanta sam și primul parametru al funcției setAge vor reprezenta două referințe diferite, dar vor indica către același obiect în memorie.

Prin urmare, dacă modificăm proprietatea acestui obiect în interiorul funcției setAge, atunci accesând proprietatea obiectului sam aceasta se va schimba și ea, deoarece, în realitate, este același obiect. În final, browserul va afișa:

Before setAge: 29 After setAge: 30

Dar dacă alt obiect este atribuit parametrului în interiorul funcției, atunci referința schimbă efectiv valoarea sa și începe să indice către o altă zonă de memorie:

function setDefault(person){

 person = {name: "Undefined", age: 0};
}

let sam = {name: "Sam", age: 29};
console.log("Before setDefault:", sam.name);
setDefault(sam);
console.log("After setDefault:", sam.name);

La transmiterea variabilei sam în funcția setDefault, parametrul acestei funcții și variabila sam vor reprezenta două link-uri diferite, dar vor indica către același obiect în memorie:

setDefault(sam);	

Dar apoi, în interiorul funcției, schimbăm valoarea parametrului:

person = {name: "Undefined", age: 0};

În final, referinței stocate în parametrul person i se atribuie un nou obiect. Dar deoarece variabila sam și parametrul person reprezintă două link-uri diferite, această atribuire nu va afecta în niciun fel obiectul sam.

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