Proxy
Proxy reprezintă un obiect care permite interceptarea execuției operațiilor asupra unui alt obiect și poate redefini comportamentul acestuia.
Pentru a crea un obiect Proxy, se utilizează constructorul Proxy():
const proxy = new Proxy(target, handler);
Constructorul Proxy acceptă doi parametri:
- target - ținta pentru crearea proxy-ului, poate fi orice obiect asupra căruia se aplică Proxy
- handler - alt obiect care definește ce operații ale obiectului target vor fi interceptate și redefinite, precum și modul în care vor fi tratate
Să examinăm un exemplu simplu:
// obiectul asupra căruia se aplică proxy
const target = { name: "Tom" };
// obiectul care definește cum va fi redefinit target
const handler = {};
// obiectul proxy
const proxy = new Proxy(target, handler);
console.log(proxy.name); // Tom
Prin urmare, în exemplul de mai sus, ținta este obiectul la care se va aplica proxierea. În acest caz, acest obiect are o proprietate numită name.
const target = {name: "Tom"};
În continuare, se creează un handler gol (un manipulator vid):
const handler = {};
În principiu, acest obiect ar trebui să definească modul în care obiectul target va fi suprascris. Dar, deocamdată, îl vom lăsa gol.
Apoi, se creează un obiect Proxy, furnizând obiectele target și handler în constructorul său.
const proxy = new Proxy(target, handler);
Proxierea obiectului (în acest caz, a obiectului target) înseamnă că prin intermediul proxy-ului putem accesa funcționalitatea acestui obiect. Și în acest caz, prin intermediul obiectului proxy, putem accesa proprietatea name a obiectului target proxiat:
console.log(proxy.name); // Tom
Și deoarece am folosit un handler gol, care nu suprascrie nimic, practic proxy se comportă ca obiectul original target.
Suprascrierea funcționalității obiectului
Mai sus am realizat proxierea obiectului, dar încă nu am suprascris comportamentul său. Cheia în acest caz este definirea handler-ului care poate intercepta accesările proprietăților obiectului proxiat. Acest handler poate defini două metode: get și set.
Metoda get și obținerea proprietăților obiectului
Metoda get interceptează accesările la o proprietate atunci când se obține valoarea acesteia și returnează o anumită valoare pentru acea proprietate:
const handler = {
get: function(target, prop, receiver) {
return o_anumită_valoare;
}
};
Metoda get are trei parametri:
- target: obiectul proxiat în sine. Datorită acestui parametru, putem accesa funcționalitatea obiectului original
- prop: numele proprietății la care se face referire
- receiver: obiectul Proxy prin intermediul căruia se realizează proxierea
Să luăm următorul exemplu:
const target = {name: "Tom"};
const handler = {
get: function(target, prop, receiver) {
return "Tomas Smith";
}
};
const proxy = new Proxy(target, handler);
console.log(proxy.name); // Tomas Smith
Aici, în handler, în metoda get, se returnează șirul "Tomas Smith":
get: function(target, prop, receiver) {
return "Tomas Smith";
}
Aceasta va avea ca rezultat faptul că, atunci când se face referire la orice proprietate a obiectului proxy, va fi returnat acest șir: "Tomas Smith".
console.log(proxy.name); // Tomas Smith
Astfel, am interceptat accesarea proprietății și am realizat o simplă suprascriere. În acest timp, putem accesa și obiectul original care este proxiat:
const target = {name: "Tom"};
const handler = {
get: function(target, prop) {
return "Name: " + target.name;
}
};
const proxy = new Proxy(target, handler);
console.log(proxy.name); // Name: Tom
Aici, handler-ul returnează șirul "Name: " + target.name, unde target.name reprezintă accesarea proprietății name a obiectului original. Desigur, logica de returnare a valorii unei proprietăți poate fi mai complexă.
Dar să luăm un obiect mai complex, cu două proprietăți:
const target = {name: "Tom", age: 37};
const handler = {
get: function(target, prop) {
return target[prop];
}
};
const proxy = new Proxy(target, handler);
console.log(proxy.name); // Tom
console.log(proxy.age); // 37
Aici, obiectul țintă are două proprietăți: name și age. În handler, interceptăm accesările la acestea, dar nu le suprascriem, ci pur și simplu returnăm valorile proprietăților obiectului original:
return target[prop];
Pentru a accesa proprietățile obiectului țintă, se folosește sintaxa cu paranteze pătrate.
De asemenea, putem verifica la ce proprietate exactă se face referire și să efectuăm o anumită suprascriere:
const target = {name: "Tom", age: 37};
const handler = {
get: function(target, prop) {
if(prop==="name")
return target.name.toUpperCase();
else
return target[prop];
}
};
const proxy = new Proxy(target, handler);
console.log(proxy.name); // TOM
console.log(proxy.age); // 37
În acest caz, dacă referirea este făcută la proprietatea name, adică la proprietatea care stochează un șir de caractere, apelăm metoda toUpperCase() pentru acest șir și îl convertim în litere mari.
Setarea proprietății și metoda set
Metoda set interceptează accesările la o proprietate atunci când i se setează o valoare:
const handler = {
set: function(target, property, value, receiver) {
}
};
Metoda set are patru parametri:
- target: obiectul original către care se face proxierea
- property: numele proprietății la care se face referire
- value: valoarea care se setează
- receiver: obiectul Proxy prin intermediul căruia se realizează proxierea
Să analizăm un exemplu:
const target = {name: "Tom", age: 37};
const handler = {
set: function(target, prop, value) {
console.log(value);
target[prop] = value;
}
};
const proxy = new Proxy(target, handler);
proxy.name = "Tomas";
console.log(proxy.name); // Tomas
proxy.age = 22;
console.log(proxy.age); // 22
În acest exemplu, în metoda set, mai întâi înregistrăm în jurnal valoarea transmisă proprietății, apoi setăm proprietatea:
target[prop] = value;
Vom face mici modificări în exemplu:
const target = {name: "Tom", age: 37};
const handler = {
set: function(target, prop, value) {
if(prop === "age" && value < 1)
console.log("Vârstă incorectă");
else
return target[prop] = value;
}
};
const proxy = new Proxy(target, handler);
proxy.name = "Tomas";
console.log(proxy.name); // Tomas
proxy.age = -199; // Vârstă incorectă
console.log(proxy.age); // 37
proxy.age = 22;
console.log(proxy.age); // 22
Aici, în metoda set a handler-ului, verificăm dacă se face setarea proprietății age și valoarea este mai mică de 1, atunci pur și simplu afișăm un mesaj despre incorectitudinea datelor. Altfel, transmitem valoarea către proprietatea obiectului original.
if (prop === "age" && value < 1)
console.log("Vârstă incorectă");
Altfel, transmitem valoarea către proprietatea obiectului original.
else
return target[prop] = value;