Raziščite vzorce JavaScript Proxy za spreminjanje obnašanja objektov. Spoznajte validacijo, virtualizacijo, sledenje in druge napredne tehnike s primeri kode.
Vzorci JavaScript Proxy: Obvladovanje spreminjanja obnašanja objektov
Objekt JavaScript Proxy ponuja močan mehanizem za prestrezanje in prilagajanje temeljnih operacij na objektih. Ta zmožnost odpira vrata širokemu naboru oblikovalskih vzorcev in naprednih tehnik za nadzor obnašanja objektov. Ta celovit vodnik raziskuje različne vzorce Proxy in ponazarja njihovo uporabo s praktičnimi primeri kode.
Kaj je JavaScript Proxy?
Objekt Proxy ovije drug objekt (cilj) in prestreže njegove operacije. Te operacije, znane kot prestrezniki (traps), vključujejo iskanje lastnosti, dodeljevanje, naštevanje in klicanje funkcij. Proxy vam omogoča, da določite logiko po meri, ki se izvede pred, po ali namesto teh operacij. Osnovni koncept Proxyja vključuje "metaprogramiranje", ki vam omogoča manipulacijo obnašanja samega jezika JavaScript.
Osnovna sintaksa za ustvarjanje Proxyja je:
const proxy = new Proxy(target, handler);
- target: Izvirni objekt, ki ga želite posredovati.
- handler: Objekt, ki vsebuje metode (prestreznike), ki določajo, kako Proxy prestreza operacije na cilju.
Pogosti prestrezniki Proxyja
Objekt handler lahko določi več prestreznikov. Tukaj je nekaj najpogosteje uporabljenih:
- get(target, property, receiver): Prestreže dostop do lastnosti (npr.
obj.property
). - set(target, property, value, receiver): Prestreže dodeljevanje lastnosti (npr.
obj.property = value
). - has(target, property): Prestreže operator
in
(npr.'property' in obj
). - deleteProperty(target, property): Prestreže operator
delete
(npr.delete obj.property
). - apply(target, thisArg, argumentsList): Prestreže klice funkcij (kadar je cilj funkcija).
- construct(target, argumentsList, newTarget): Prestreže operator
new
(kadar je cilj konstruktorska funkcija). - getPrototypeOf(target): Prestreže klice
Object.getPrototypeOf()
. - setPrototypeOf(target, prototype): Prestreže klice
Object.setPrototypeOf()
. - isExtensible(target): Prestreže klice
Object.isExtensible()
. - preventExtensions(target): Prestreže klice
Object.preventExtensions()
. - getOwnPropertyDescriptor(target, property): Prestreže klice
Object.getOwnPropertyDescriptor()
. - defineProperty(target, property, descriptor): Prestreže klice
Object.defineProperty()
. - ownKeys(target): Prestreže klice
Object.getOwnPropertyNames()
inObject.getOwnPropertySymbols()
.
Vzorci Proxy in primeri uporabe
Raziščimo nekaj pogostih vzorcev Proxy in kako jih je mogoče uporabiti v resničnih scenarijih:
1. Validacija
Vzorec validacije uporablja Proxy za uveljavljanje omejitev pri dodeljevanju lastnosti. To je uporabno za zagotavljanje integritete podatkov.
const validator = {
set: function(obj, prop, value) {
if (prop === 'age') {
if (!Number.isInteger(value)) {
throw new TypeError('Starost ni celo število');
}
if (value < 0) {
throw new RangeError('Starost mora biti nenegativno celo število');
}
}
// Privzeto obnašanje za shranjevanje vrednosti
obj[prop] = value;
// Označi uspeh
return true;
}
};
let person = {};
let proxy = new Proxy(person, validator);
proxy.age = 25; // Veljavno
console.log(proxy.age); // Izhod: 25
try {
proxy.age = 'mlad'; // Sproži TypeError
} catch (e) {
console.log(e); // Izhod: TypeError: Starost ni celo število
}
try {
proxy.age = -10; // Sproži RangeError
} catch (e) {
console.log(e); // Izhod: RangeError: Starost mora biti nenegativno celo število
}
Primer: Predstavljajte si platformo za e-trgovino, kjer je potrebna validacija uporabniških podatkov. Proxy lahko uveljavi pravila glede starosti, oblike e-pošte, moči gesla in drugih polj ter tako prepreči shranjevanje neveljavnih podatkov.
2. Virtualizacija (leno nalaganje)
Virtualizacija, znana tudi kot leno nalaganje, odloži nalaganje dragih virov, dokler niso dejansko potrebni. Proxy lahko deluje kot nadomestni znak za resnični objekt in ga naloži šele, ko se dostopi do njegove lastnosti.
const expensiveData = {
load: function() {
console.log('Nalaganje dragih podatkov...');
// Simulacija časovno potratne operacije (npr. pridobivanje iz baze podatkov)
return new Promise(resolve => {
setTimeout(() => {
resolve({
data: 'To so dragi podatki'
});
}, 2000);
});
}
};
const lazyLoadHandler = {
get: function(target, prop) {
if (prop === 'data') {
console.log('Dostopanje do podatkov, nalaganje, če je potrebno...');
return target.load().then(result => {
target.data = result.data; // Shrani naložene podatke
return result.data;
});
} else {
return target[prop];
}
}
};
const lazyData = new Proxy(expensiveData, lazyLoadHandler);
console.log('Začetni dostop...');
lazyData.data.then(data => {
console.log('Podatki:', data); // Izhod: Podatki: To so dragi podatki
});
console.log('Naslednji dostop...');
lazyData.data.then(data => {
console.log('Podatki:', data); // Izhod: Podatki: To so dragi podatki (naloženi iz predpomnilnika)
});
Primer: Predstavljajte si veliko platformo družbenih medijev z uporabniškimi profili, ki vsebujejo številne podrobnosti in povezane medije. Takojšnje nalaganje vseh podatkov profila je lahko neučinkovito. Virtualizacija s Proxyjem omogoča, da se najprej naložijo osnovne informacije o profilu, dodatne podrobnosti ali medijska vsebina pa šele, ko uporabnik preide na te odseke.
3. Dnevniško beleženje in sledenje
Proxyji se lahko uporabljajo za sledenje dostopa do lastnosti in njihovih sprememb. To je dragoceno za odpravljanje napak, revizijo in spremljanje zmogljivosti.
const logHandler = {
get: function(target, prop, receiver) {
console.log(`GET ${prop}`);
return Reflect.get(target, prop, receiver);
},
set: function(target, prop, value) {
console.log(`SET ${prop} na ${value}`);
target[prop] = value;
return true;
}
};
let obj = { name: 'Alice' };
let proxy = new Proxy(obj, logHandler);
console.log(proxy.name); // Izhod: GET name, Alice
proxy.age = 30; // Izhod: SET age na 30
Primer: V aplikaciji za sodelovalno urejanje dokumentov lahko Proxy sledi vsaki spremembi vsebine dokumenta. To omogoča ustvarjanje revizijske sledi, funkcionalnost razveljavitve/ponovitve (undo/redo) in vpogled v prispevke uporabnikov.
4. Pogledi samo za branje
Proxyji lahko ustvarijo poglede objektov samo za branje in tako preprečijo nenamerne spremembe. To je uporabno za zaščito občutljivih podatkov.
const readOnlyHandler = {
set: function(target, prop, value) {
console.error(`Ni mogoče nastaviti lastnosti ${prop}: objekt je samo za branje`);
return false; // Označi, da operacija set ni uspela
},
deleteProperty: function(target, prop) {
console.error(`Ni mogoče izbrisati lastnosti ${prop}: objekt je samo za branje`);
return false; // Označi, da operacija brisanja ni uspela
}
};
let data = { name: 'Bob', age: 40 };
let readOnlyData = new Proxy(data, readOnlyHandler);
try {
readOnlyData.age = 41; // Sproži napako
} catch (e) {
console.log(e); // Napaka ni sprožena, ker prestreznik 'set' vrne false.
}
try {
delete readOnlyData.name; // Sproži napako
} catch (e) {
console.log(e); // Napaka ni sprožena, ker prestreznik 'deleteProperty' vrne false.
}
console.log(data.age); // Izhod: 40 (nespremenjeno)
Primer: Predstavljajte si finančni sistem, kjer imajo nekateri uporabniki dostop do informacij o računu samo za branje. Proxy se lahko uporabi za preprečevanje spreminjanja stanj na računu ali drugih ključnih podatkov s strani teh uporabnikov.
5. Privzete vrednosti
Proxy lahko zagotovi privzete vrednosti za manjkajoče lastnosti. To poenostavi kodo in se izogne preverjanju za null/undefined vrednosti.
const defaultValuesHandler = {
get: function(target, prop, receiver) {
if (!(prop in target)) {
console.log(`Lastnost ${prop} ni najdena, vračam privzeto vrednost.`);
return 'Privzeta vrednost'; // Ali katera koli druga ustrezna privzeta vrednost
}
return Reflect.get(target, prop, receiver);
}
};
let config = { apiUrl: 'https://api.example.com' };
let configWithDefaults = new Proxy(config, defaultValuesHandler);
console.log(configWithDefaults.apiUrl); // Izhod: https://api.example.com
console.log(configWithDefaults.timeout); // Izhod: Lastnost timeout ni najdena, vračam privzeto vrednost. Privzeta vrednost
Primer: V sistemu za upravljanje konfiguracije lahko Proxy zagotovi privzete vrednosti za manjkajoče nastavitve. Na primer, če konfiguracijska datoteka ne določa časovne omejitve za povezavo z bazo podatkov, lahko Proxy vrne vnaprej določeno privzeto vrednost.
6. Metapodatki in opombe
Proxyji lahko objektom pripnejo metapodatke ali opombe ter tako zagotovijo dodatne informacije brez spreminjanja izvirnega objekta.
const metadataHandler = {
get: function(target, prop, receiver) {
if (prop === '__metadata__') {
return { description: 'To so metapodatki za objekt' };
}
return Reflect.get(target, prop, receiver);
}
};
let article = { title: 'Uvod v Proxyje', content: '...' };
let articleWithMetadata = new Proxy(article, metadataHandler);
console.log(articleWithMetadata.title); // Izhod: Uvod v Proxyje
console.log(articleWithMetadata.__metadata__.description); // Izhod: To so metapodatki za objekt
Primer: V sistemu za upravljanje vsebin lahko Proxy člankom pripne metapodatke, kot so informacije o avtorju, datum objave in ključne besede. Te metapodatke je mogoče uporabiti za iskanje, filtriranje in kategorizacijo vsebin.
7. Prestrezanje funkcij
Proxyji lahko prestrežejo klice funkcij, kar vam omogoča dodajanje dnevniškega beleženja, validacije ali druge logike pred- ali po-obdelave.
const functionInterceptor = {
apply: function(target, thisArg, argumentsList) {
console.log('Klicanje funkcije z argumenti:', argumentsList);
const result = target.apply(thisArg, argumentsList);
console.log('Funkcija je vrnila:', result);
return result;
}
};
function add(a, b) {
return a + b;
}
let proxiedAdd = new Proxy(add, functionInterceptor);
let sum = proxiedAdd(5, 3); // Izhod: Klicanje funkcije z argumenti: [5, 3], Funkcija je vrnila: 8
console.log(sum); // Izhod: 8
Primer: V bančni aplikaciji lahko Proxy prestreže klice transakcijskih funkcij, beleži vsako transakcijo in izvaja preverjanja za odkrivanje goljufij pred izvedbo transakcije.
8. Prestrezanje konstruktorjev
Proxyji lahko prestrežejo klice konstruktorjev, kar vam omogoča prilagajanje ustvarjanja objektov.
const constructorInterceptor = {
construct: function(target, argumentsList, newTarget) {
console.log('Ustvarjanje nove instance', target.name, 'z argumenti:', argumentsList);
const obj = new target(...argumentsList);
console.log('Nova instanca ustvarjena:', obj);
return obj;
}
};
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
let ProxiedPerson = new Proxy(Person, constructorInterceptor);
let person = new ProxiedPerson('Alice', 28); // Izhod: Ustvarjanje nove instance Person z argumenti: ['Alice', 28], Nova instanca ustvarjena: Person { name: 'Alice', age: 28 }
console.log(person);
Primer: V ogrodju za razvoj iger lahko Proxy prestreže ustvarjanje igralnih objektov, jim samodejno dodeli edinstvene ID-je, doda privzete komponente in jih registrira v igralnem pogonu.
Napredni premisleki
- Zmogljivost: Čeprav Proxyji ponujajo prilagodljivost, lahko povzročijo dodatno obremenitev zmogljivosti. Pomembno je, da primerjate in profilirate svojo kodo, da zagotovite, da prednosti uporabe Proxyjev odtehtajo stroške zmogljivosti, zlasti v aplikacijah, kjer je zmogljivost ključnega pomena.
- Združljivost: Proxyji so razmeroma nov dodatek k JavaScriptu, zato jih starejši brskalniki morda ne podpirajo. Uporabite zaznavanje funkcionalnosti ali polyfille za zagotovitev združljivosti s starejšimi okolji.
- Preklicni Proxyji: Metoda
Proxy.revocable()
ustvari Proxy, ki ga je mogoče preklicati. Preklic Proxyja prepreči nadaljnje prestrezanje operacij. To je lahko koristno za varnostne namene ali upravljanje z viri. - Reflect API: API Reflect ponuja metode za izvajanje privzetega obnašanja prestreznikov Proxyja. Uporaba
Reflect
zagotavlja, da se vaša koda Proxy obnaša dosledno s specifikacijo jezika.
Zaključek
JavaScript Proxyji zagotavljajo močan in vsestranski mehanizem za prilagajanje obnašanja objektov. Z obvladovanjem različnih vzorcev Proxy lahko pišete bolj robustno, vzdržljivo in učinkovito kodo. Ne glede na to, ali implementirate validacijo, virtualizacijo, sledenje ali druge napredne tehnike, Proxyji ponujajo prilagodljivo rešitev za nadzor dostopa do objektov in manipulacije z njimi. Vedno upoštevajte posledice za zmogljivost in zagotovite združljivost s ciljnimi okolji. Proxyji so ključno orodje v arzenalu sodobnega razvijalca JavaScript, ki omogočajo močne tehnike metaprogramiranja.
Nadaljnje raziskovanje
- Mozilla Developer Network (MDN): JavaScript Proxy
- Exploring JavaScript Proxies: Članek Smashing Magazine