Izpētiet JavaScript Proxy modeļus objektu uzvedības modificēšanai. Uzziniet par validāciju, virtualizāciju, izsekošanu un citām progresīvām metodēm ar kodu piemēriem.
JavaScript Proxy modeļi: objektu uzvedības modificēšanas apgūšana
JavaScript Proxy objekts nodrošina jaudīgu mehānismu, lai pārtvertu un pielāgotu fundamentālas darbības ar objektiem. Šī spēja paver durvis plašam dizaina modeļu un progresīvu tehniku klāstam objektu uzvedības kontrolēšanai. Šajā visaptverošajā rokasgrāmatā tiek pētīti dažādi Proxy modeļi, ilustrējot to pielietojumu ar praktiskiem koda piemēriem.
Kas ir JavaScript Proxy?
Proxy objekts "ietin" citu objektu (mērķi) un pārtver tā darbības. Šīs darbības, kas pazīstamas kā lamatas (traps), ietver īpašību nolasīšanu, piešķiršanu, uzskaitīšanu un funkciju izsaukšanu. Proxy ļauj definēt pielāgotu loģiku, kas jāizpilda pirms, pēc vai šo darbību vietā. Proxy pamatkoncepcija ietver "metaprogrammēšanu", kas ļauj manipulēt ar pašu JavaScript valodas uzvedību.
Pamata sintakse Proxy izveidei ir:
const proxy = new Proxy(target, handler);
- target: Sākotnējais objekts, kuru vēlaties proksēt.
- handler: Objekts, kas satur metodes (lamatas), kuras definē, kā Proxy pārtver darbības ar mērķa objektu.
Biežākās Proxy lamatas (traps)
Handler objekts var definēt vairākas lamatas. Šeit ir dažas no visbiežāk izmantotajām:
- get(target, property, receiver): Pārtver īpašības piekļuvi (piem.,
obj.property
). - set(target, property, value, receiver): Pārtver īpašības piešķiršanu (piem.,
obj.property = value
). - has(target, property): Pārtver
in
operatoru (piem.,'property' in obj
). - deleteProperty(target, property): Pārtver
delete
operatoru (piem.,delete obj.property
). - apply(target, thisArg, argumentsList): Pārtver funkciju izsaukumus (kad mērķis ir funkcija).
- construct(target, argumentsList, newTarget): Pārtver
new
operatoru (kad mērķis ir konstruktora funkcija). - getPrototypeOf(target): Pārtver izsaukumus uz
Object.getPrototypeOf()
. - setPrototypeOf(target, prototype): Pārtver izsaukumus uz
Object.setPrototypeOf()
. - isExtensible(target): Pārtver izsaukumus uz
Object.isExtensible()
. - preventExtensions(target): Pārtver izsaukumus uz
Object.preventExtensions()
. - getOwnPropertyDescriptor(target, property): Pārtver izsaukumus uz
Object.getOwnPropertyDescriptor()
. - defineProperty(target, property, descriptor): Pārtver izsaukumus uz
Object.defineProperty()
. - ownKeys(target): Pārtver izsaukumus uz
Object.getOwnPropertyNames()
unObject.getOwnPropertySymbols()
.
Proxy modeļi un pielietojuma gadījumi
Izpētīsim dažus izplatītus Proxy modeļus un to, kā tos var pielietot reālās dzīves scenārijos:
1. Validācija
Validācijas modelis izmanto Proxy, lai ieviestu ierobežojumus īpašību piešķiršanai. Tas ir noderīgi datu integritātes nodrošināšanai.
const validator = {
set: function(obj, prop, value) {
if (prop === 'age') {
if (!Number.isInteger(value)) {
throw new TypeError('Vecums nav vesels skaitlis');
}
if (value < 0) {
throw new RangeError('Vecumam jābūt nenegatīvam veselam skaitlim');
}
}
// Noklusējuma darbība, lai saglabātu vērtību
obj[prop] = value;
// Norāda uz veiksmīgu izpildi
return true;
}
};
let person = {};
let proxy = new Proxy(person, validator);
proxy.age = 25; // Derīgs
console.log(proxy.age); // Izvada: 25
try {
proxy.age = 'young'; // Izmet TypeError
} catch (e) {
console.log(e); // Izvada: TypeError: Vecums nav vesels skaitlis
}
try {
proxy.age = -10; // Izmet RangeError
} catch (e) {
console.log(e); // Izvada: RangeError: Vecumam jābūt nenegatīvam veselam skaitlim
}
Piemērs: Apsveriet e-komercijas platformu, kur lietotāja datiem nepieciešama validācija. Proxy var ieviest noteikumus par vecumu, e-pasta formātu, paroles stiprumu un citiem laukiem, novēršot nederīgu datu saglabāšanu.
2. Virtualizācija (slinkā ielāde)
Virtualizācija, pazīstama arī kā slinkā ielāde (lazy loading), aizkavē dārgu resursu ielādi, līdz tie ir faktiski nepieciešami. Proxy var darboties kā aizstājējs reālajam objektam, ielādējot to tikai tad, kad tiek piekļūts kādai īpašībai.
const expensiveData = {
load: function() {
console.log('Ielādē dārgos datus...');
// Simulē laikietilpīgu operāciju (piem., ielāde no datu bāzes)
return new Promise(resolve => {
setTimeout(() => {
resolve({
data: 'Šie ir dārgie dati'
});
}, 2000);
});
}
};
const lazyLoadHandler = {
get: function(target, prop) {
if (prop === 'data') {
console.log('Piekļūst datiem, ielādējot tos, ja nepieciešams...');
return target.load().then(result => {
target.data = result.data; // Saglabā ielādētos datus
return result.data;
});
} else {
return target[prop];
}
}
};
const lazyData = new Proxy(expensiveData, lazyLoadHandler);
console.log('Sākotnējā piekļuve...');
lazyData.data.then(data => {
console.log('Dati:', data); // Izvada: Dati: Šie ir dārgie dati
});
console.log('Nākamā piekļuve...');
lazyData.data.then(data => {
console.log('Dati:', data); // Izvada: Dati: Šie ir dārgie dati (ielādēti no kešatmiņas)
});
Piemērs: Iedomājieties lielu sociālo mediju platformu ar lietotāju profiliem, kas satur daudzas detaļas un saistītos medijus. Visu profila datu tūlītēja ielāde var būt neefektīva. Virtualizācija ar Proxy ļauj vispirms ielādēt pamata profila informāciju un pēc tam ielādēt papildu detaļas vai multivides saturu tikai tad, kad lietotājs pāriet uz šīm sadaļām.
3. Žurnālēšana un izsekošana
Proxy var izmantot, lai izsekotu īpašību piekļuvi un modifikācijas. Tas ir vērtīgi atkļūdošanai, auditēšanai un veiktspējas uzraudzībai.
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} uz ${value}`);
target[prop] = value;
return true;
}
};
let obj = { name: 'Alice' };
let proxy = new Proxy(obj, logHandler);
console.log(proxy.name); // Izvada: GET name, Alice
proxy.age = 30; // Izvada: SET age uz 30
Piemērs: Kopdarba dokumentu rediģēšanas lietojumprogrammā Proxy var izsekot katrai izmaiņai, kas veikta dokumenta saturā. Tas ļauj izveidot audita pierakstu, nodrošināt atsaukšanas/atcelšanas funkcionalitāti un sniegt ieskatu lietotāju ieguldījumā.
4. Tikai lasāmi skati
Proxy var izveidot tikai lasāmus objektu skatus, novēršot nejaušas modifikācijas. Tas ir noderīgi, lai aizsargātu sensitīvus datus.
const readOnlyHandler = {
set: function(target, prop, value) {
console.error(`Nevar iestatīt īpašību ${prop}: objekts ir tikai lasāms`);
return false; // Norāda, ka set operācija neizdevās
},
deleteProperty: function(target, prop) {
console.error(`Nevar dzēst īpašību ${prop}: objekts ir tikai lasāms`);
return false; // Norāda, ka delete operācija neizdevās
}
};
let data = { name: 'Bob', age: 40 };
let readOnlyData = new Proxy(data, readOnlyHandler);
try {
readOnlyData.age = 41; // Izmet kļūdu
} catch (e) {
console.log(e); // Kļūda netiek izmesta, jo 'set' lamata atgriež false.
}
try {
delete readOnlyData.name; // Izmet kļūdu
} catch (e) {
console.log(e); // Kļūda netiek izmesta, jo 'deleteProperty' lamata atgriež false.
}
console.log(data.age); // Izvada: 40 (nemainīts)
Piemērs: Apsveriet finanšu sistēmu, kur dažiem lietotājiem ir tikai lasīšanas piekļuve konta informācijai. Proxy var izmantot, lai liegtu šiem lietotājiem modificēt konta atlikumus vai citus kritiskus datus.
5. Noklusējuma vērtības
Proxy var nodrošināt noklusējuma vērtības trūkstošajām īpašībām. Tas vienkāršo kodu un ļauj izvairīties no null/undefined pārbaudēm.
const defaultValuesHandler = {
get: function(target, prop, receiver) {
if (!(prop in target)) {
console.log(`Īpašība ${prop} nav atrasta, atgriežot noklusējuma vērtību.`);
return 'Noklusējuma vērtība'; // Vai jebkura cita piemērota noklusējuma vērtība
}
return Reflect.get(target, prop, receiver);
}
};
let config = { apiUrl: 'https://api.example.com' };
let configWithDefaults = new Proxy(config, defaultValuesHandler);
console.log(configWithDefaults.apiUrl); // Izvada: https://api.example.com
console.log(configWithDefaults.timeout); // Izvada: Īpašība timeout nav atrasta, atgriežot noklusējuma vērtību. Noklusējuma vērtība
Piemērs: Konfigurācijas pārvaldības sistēmā Proxy var nodrošināt noklusējuma vērtības trūkstošiem iestatījumiem. Piemēram, ja konfigurācijas failā nav norādīts datu bāzes savienojuma taimauts, Proxy var atgriezt iepriekš definētu noklusējuma vērtību.
6. Metadati un anotācijas
Proxy var pievienot metadatus vai anotācijas objektiem, nodrošinot papildu informāciju, nemainot sākotnējo objektu.
const metadataHandler = {
get: function(target, prop, receiver) {
if (prop === '__metadata__') {
return { description: 'Šie ir objekta metadati' };
}
return Reflect.get(target, prop, receiver);
}
};
let article = { title: 'Ievads Proxy', content: '...' };
let articleWithMetadata = new Proxy(article, metadataHandler);
console.log(articleWithMetadata.title); // Izvada: Ievads Proxy
console.log(articleWithMetadata.__metadata__.description); // Izvada: Šie ir objekta metadati
Piemērs: Satura pārvaldības sistēmā Proxy var pievienot rakstiem metadatus, piemēram, autora informāciju, publicēšanas datumu un atslēgvārdus. Šos metadatus var izmantot satura meklēšanai, filtrēšanai un kategorizēšanai.
7. Funkciju pārtveršana
Proxy var pārtvert funkciju izsaukumus, ļaujot pievienot žurnālēšanu, validāciju vai citu pirms- vai pēcapstrādes loģiku.
const functionInterceptor = {
apply: function(target, thisArg, argumentsList) {
console.log('Izsauc funkciju ar argumentiem:', argumentsList);
const result = target.apply(thisArg, argumentsList);
console.log('Funkcija atgrieza:', result);
return result;
}
};
function add(a, b) {
return a + b;
}
let proxiedAdd = new Proxy(add, functionInterceptor);
let sum = proxiedAdd(5, 3); // Izvada: Izsauc funkciju ar argumentiem: [5, 3], Funkcija atgrieza: 8
console.log(sum); // Izvada: 8
Piemērs: Banku lietojumprogrammā Proxy var pārtvert izsaukumus uz transakciju funkcijām, reģistrējot katru transakciju un veicot krāpšanas atklāšanas pārbaudes pirms transakcijas izpildes.
8. Konstruktoru pārtveršana
Proxy var pārtvert konstruktoru izsaukumus, ļaujot pielāgot objektu izveidi.
const constructorInterceptor = {
construct: function(target, argumentsList, newTarget) {
console.log('Izveido jaunu instanci klasei', target.name, 'ar argumentiem:', argumentsList);
const obj = new target(...argumentsList);
console.log('Jauna instance izveidota:', 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); // Izvada: Izveido jaunu instanci klasei Person ar argumentiem: ['Alice', 28], Jauna instance izveidota: Person { name: 'Alice', age: 28 }
console.log(person);
Piemērs: Spēļu izstrādes ietvarā Proxy var pārtvert spēles objektu izveidi, automātiski piešķirot unikālus ID, pievienojot noklusējuma komponentes un reģistrējot tos spēles dzinējā.
Papildu apsvērumi
- Veiktspēja: Lai gan Proxy piedāvā elastību, tie var radīt veiktspējas pieskaitāmās izmaksas. Ir svarīgi veikt etalonuzdevumus un profilēt kodu, lai nodrošinātu, ka Proxy izmantošanas priekšrocības atsver veiktspējas izmaksas, īpaši veiktspējai kritiskās lietojumprogrammās.
- Saderība: Proxy ir salīdzinoši nesens papildinājums JavaScript, tāpēc vecākas pārlūkprogrammas tos var neatbalstīt. Izmantojiet funkciju noteikšanu vai polifilus, lai nodrošinātu saderību ar vecākām vidēm.
- Atsaucamie Proxy: Metode
Proxy.revocable()
izveido Proxy, kuru var atsaukt. Proxy atsaukšana neļauj turpmākām darbībām tikt pārtvertām. Tas var būt noderīgi drošības vai resursu pārvaldības nolūkos. - Reflect API: Reflect API nodrošina metodes, lai veiktu Proxy lamatu noklusējuma darbību.
Reflect
izmantošana nodrošina, ka jūsu Proxy kods darbojas saskaņoti ar valodas specifikāciju.
Noslēgums
JavaScript Proxy nodrošina jaudīgu un daudzpusīgu mehānismu objektu uzvedības pielāgošanai. Apgūstot dažādus Proxy modeļus, jūs varat rakstīt stabilāku, uzturamāku un efektīvāku kodu. Neatkarīgi no tā, vai jūs īstenojat validāciju, virtualizāciju, izsekošanu vai citas progresīvas metodes, Proxy piedāvā elastīgu risinājumu, lai kontrolētu, kā objektiem tiek piekļūts un kā tie tiek manipulēti. Vienmēr apsveriet veiktspējas ietekmi un nodrošiniet saderību ar mērķa vidēm. Proxy ir galvenais instruments mūsdienu JavaScript izstrādātāja arsenālā, kas nodrošina jaudīgas metaprogrammēšanas tehnikas.
Tālākai izpētei
- Mozilla Developer Network (MDN): JavaScript Proxy
- Exploring JavaScript Proxies: Smashing Magazine raksts