JavaScript'ning Stage 3 xususiy metod dekoratorlari kuchini o'rganing. Klasslarni yaxshilash, validatsiyani joriy etish va amaliy misollar bilan toza, qo'llab-quvvatlanadigan kod yozishni o'rganing.
JavaScript Xususiy Metod Dekoratorlari: Klassni Kengaytirish va Validatsiya qilishga Chuqur Kirish
Zamonaviy JavaScript doimiy rivojlanish holatida bo'lib, dasturchilarga yanada ifodali, qo'llab-quvvatlanadigan va mustahkam kod yozish imkonini beruvchi kuchli yangi xususiyatlarni taqdim etmoqda. Bu xususiyatlar orasida eng kutilganlaridan biri dekoratorlardir. TC39 jarayonida 3-bosqichga (Stage 3) yetib kelgan dekoratorlar tilning standart qismiga aylanish arafasida turibdi va ular metaprogrammalash hamda klassga asoslangan arxitekturaga bo'lgan yondashuvimizni inqilob qilishni va'da qilmoqda.
Dekoratorlar turli klass elementlariga qo'llanilishi mumkin bo'lsa-da, ushbu maqola ayniqsa kuchli bir dasturga e'tibor qaratadi: xususiy metod dekoratorlari. Biz ushbu ixtisoslashtirilgan dekoratorlar klasslarimizning ichki ishlashini qanday yaxshilash va tasdiqlash imkonini berishini, haqiqiy inkapsulyatsiyani rag'batlantirish bilan birga kuchli, qayta ishlatiladigan xulq-atvorlarni qo'shishini o'rganamiz. Bu global miqyosda murakkab ilovalar, kutubxonalar va freymvorklarni yaratishda o'yin qoidalarini o'zgartiruvchi omil bo'ladi.
Asoslar: Dekoratorlar Aslida Nima?
O'z mohiyatiga ko'ra, dekoratorlar metaprogrammalashning bir shaklidir. Sodda qilib aytganda, ular boshqa funksiyalar, klasslar yoki xususiyatlarni o'zgartiradigan maxsus turdagi funksiyalardir. Ular @ifoda formatidan foydalanib, kod elementlariga ularning asosiy realizatsiyasini o'zgartirmasdan xulq-atvor qo'shish uchun deklarativ sintaksisni taqdim etadi.
Buni funksionallik qatlamlarini qo'shish deb o'ylang. Asosiy biznes mantig'ingizni log yozish, vaqtni o'lchash yoki validatsiya kabi masalalar bilan chalkashtirish o'rniga, siz metodni ushbu imkoniyatlar bilan 'bezashingiz' mumkin. Bu Aspektga Yo'naltirilgan Dasturlash (AOP) va Yagona Mas'uliyat Printsipi kabi kuchli dasturiy ta'minot muhandisligi tamoyillariga mos keladi, bunda funksiya yoki klassning o'zgarishi uchun faqat bitta sabab bo'lishi kerak.
Dekoratorlar quyidagilarga qo'llanilishi mumkin:
- Klasslar
- Metodlar (ham ochiq, ham xususiy)
- Maydonlar (ham ochiq, ham xususiy)
- Kirish vositalari (getters/setters)
Bizning bugungi diqqatimiz dekoratorlarning boshqa zamonaviy JavaScript xususiyati - xususiy klass a'zolari bilan kuchli birikmasiga qaratilgan.
Zaruriy Shart: Xususiy Klass Xususiyatlarini Tushunish
Xususiy metodni samarali bezashdan oldin, biz uni nima xususiy qilishini tushunishimiz kerak. Ko'p yillar davomida JavaScript dasturchilari pastki chiziq prefiksi (masalan, `_myPrivateMethod`) kabi konvensiyalardan foydalanib maxfiylikni simulyatsiya qilishgan. Biroq, bu shunchaki konvensiya edi; metod hali ham ommaviy ravishda mavjud edi.
Zamonaviy JavaScript reshotka prefiksi (`#`) yordamida haqiqiy xususiy klass a'zolarini taqdim etdi.
Ushbu klassni ko'rib chiqing:
class PaymentGateway {
#apiKey;
constructor(apiKey) {
this.#apiKey = apiKey;
}
#createAuthHeader() {
// Xavfsiz sarlavha yaratish uchun ichki mantiq
// Bu hech qachon klassdan tashqarida chaqirilmasligi kerak
const timestamp = Date.now();
return `API-Key ${this.#apiKey}:${timestamp}`;
}
submitPayment(data) {
const headers = this.#createAuthHeader();
console.log('To\'lovni sarlavha bilan yuborish:', headers);
// ... to'lov API'siga fetch so'rovi
}
}
const gateway = new PaymentGateway('my-secret-key');
// Bu kutilganidek ishlaydi
gateway.submitPayment({ amount: 100 });
// Bu SyntaxError yoki TypeError xatosini beradi
// gateway.#createAuthHeader(); // Xato: Xususiy maydon '#createAuthHeader' o'rab turuvchi klassda e'lon qilinishi kerak
`#createAuthHeader` metodi haqiqatan ham xususiydir. Unga faqat `PaymentGateway` klassi ichidan kirish mumkin, bu esa kuchli inkapsulyatsiyani ta'minlaydi. Bu xususiy metod dekoratorlari quriladigan poydevordir.
Xususiy Metod Dekoratorining Anatomiyasi
Xususiy metodni bezash, maxfiylikning tabiati tufayli ochiq metodni bezashdan biroz farq qiladi. Dekorator metod funksiyasini to'g'ridan-to'g'ri olmaydi. Buning o'rniga, u maqsad qiymatini va xususiy a'zo bilan xavfsiz muloqot qilish usulini ta'minlovchi `context` obyektini oladi.
Metod dekoratori funksiyasining imzosi: `function(target, context)`
- `target`: Metod funksiyasining o'zi (ochiq metodlar uchun) yoki xususiy metodlar uchun `undefined`. Xususiy metodlar uchun metodga kirish uchun `context` obyektidan foydalanishimiz kerak.
- `context`: Bezatilgan element haqida metama'lumotlarni o'z ichiga olgan obyekt. Xususiy metod uchun u shunday ko'rinadi:
kind: 'method' satri.name: Metod nomi satr sifatida, masalan, '#myMethod'.access: Xususiy a'zoning qiymatini o'qish yoki yozish uchun `get()` va `set()` funksiyalari bo'lgan obyekt. Bu xususiy dekoratorlar bilan ishlashning kalitidir.private: `true` mantiqiy qiymati.static: Metod statik ekanligini ko'rsatuvchi mantiqiy qiymat.addInitializer: Klass aniqlanganda bir marta ishga tushadigan mantiqni ro'yxatdan o'tkazish uchun funksiya.
Oddiy Log Yozish Dekoratori
Keling, xususiy metod chaqirilganda shunchaki log yozadigan oddiy dekorator yarataylik. Ushbu misol asl metodni olish uchun `context.access.get()` dan qanday foydalanishni aniq ko'rsatib beradi.
function logCall(target, context) {
const methodName = context.name;
// Bu dekorator asl metodni almashtiradigan yangi funksiyani qaytaradi
return function (...args) {
console.log(`Xususiy metod chaqirilmoqda: ${methodName}`);
// Kirish obyekti yordamida asl metodni oling
const originalMethod = context.access.get(this);
// Asl metodni to'g'ri 'this' konteksti va argumentlar bilan chaqiring
return originalMethod.apply(this, args);
};
}
class DataService {
@logCall
#fetchData(url) {
console.log(` -> ${url} dan ma'lumotlar olinmoqda...`);
return { data: 'Sample Data' };
}
getUser() {
return this.#fetchData('/api/user/1');
}
}
const service = new DataService();
service.getUser();
// Konsol Chiqishi:
// Xususiy metod chaqirilmoqda: #fetchData
// -> /api/user/1 dan ma'lumotlar olinmoqda...
Ushbu misolda `@logCall` dekoratori `#fetchData` ni yangi funksiya bilan almashtiradi. Bu yangi funksiya avval xabar yozadi, so'ngra asl `#fetchData` funksiyasiga havola olish uchun `context.access.get(this)` dan foydalanadi va nihoyat uni `.apply()` yordamida chaqiradi. Asl funksiyani o'rashning bu namunasi ko'pchilik dekoratorlardan foydalanish holatlarining markazida turadi.
Amaliy Qo'llash 1: Metodni Kengaytirish va AOP
Dekoratorlarning asosiy qo'llanilishidan biri kesishuvchi masalalarni - dasturning ko'p qismlariga ta'sir qiluvchi xulq-atvorlarni - asosiy mantiqni ifloslantirmasdan qo'shishdir. Bu Aspektga Yo'naltirilgan Dasturlash (AOP) ning mohiyatidir.
Misol: @logExecutionTime bilan Ishlash Vaqtini O'lchash
Katta miqyosdagi ilovalarda ishlashdagi to'siqlarni aniqlash juda muhim. Har bir metodga vaqtni o'lchash mantig'ini (`console.time`, `console.timeEnd`) qo'lda qo'shish zerikarli va xatolarga moyil. Dekorator buni oddiy qilib qo'yadi.
function logExecutionTime(target, context) {
const methodName = context.name;
return function (...args) {
console.log(`${methodName} bajarilmoqda...`);
const start = performance.now();
const originalMethod = context.access.get(this);
const result = originalMethod.apply(this, args);
const end = performance.now();
console.log(`${methodName} ning bajarilishi ${(end - start).toFixed(2)}ms da yakunlandi.`);
return result;
};
}
class ReportGenerator {
@logExecutionTime
#processLargeDataset() {
// Vaqt talab qiladigan operatsiyani simulyatsiya qilish
let sum = 0;
for (let i = 0; i < 100000000; i++) {
sum += Math.sqrt(i);
}
return sum;
}
generate() {
console.log('Hisobot yaratish boshlanmoqda.');
const result = this.#processLargeDataset();
console.log('Hisobot yaratish yakunlandi.');
return result;
}
}
const generator = new ReportGenerator();
generator.generate();
// Konsol Chiqishi:
// Hisobot yaratish boshlanmoqda.
// #processLargeDataset bajarilmoqda...
// #processLargeDataset ning bajarilishi 150.75ms da yakunlandi. (Vaqt o'zgarishi mumkin)
// Hisobot yaratish yakunlandi.
Birgina `@logExecutionTime` qatori bilan biz xususiy metodimizga murakkab ishlash monitoringini qo'shdik. Ushbu dekorator endi bizning butun kod bazamizdagi har qanday ochiq yoki xususiy metodga qo'llanilishi mumkin bo'lgan qayta ishlatiladigan vositadir.
Misol: @memoize bilan Keshlashtirish/Memoizatsiya
Hisoblash uchun qimmat bo'lgan va sof (ya'ni, bir xil kirish uchun bir xil chiqishni qaytaradigan) xususiy metodlar uchun natijalarni keshlashtirish ishlashni sezilarli darajada yaxshilashi mumkin. Bu memoizatsiya deb ataladi.
function memoize(target, context) {
// WeakMap dan foydalanish klass namunasini axlat yig'uvchi tomonidan tozalanishiga imkon beradi
const cache = new WeakMap();
return function (...args) {
if (!cache.has(this)) {
cache.set(this, new Map());
}
const instanceCache = cache.get(this);
const cacheKey = JSON.stringify(args);
if (instanceCache.has(cacheKey)) {
console.log(`[Memoize] ${context.name} uchun keshdagi natija qaytarilmoqda`);
return instanceCache.get(cacheKey);
}
const originalMethod = context.access.get(this);
const result = originalMethod.apply(this, args);
instanceCache.set(cacheKey, result);
console.log(`[Memoize] ${context.name} uchun yangi natija keshlanmoqda`);
return result;
};
}
class FinanceCalculator {
@memoize
#calculateComplexTax(income, region) {
console.log(' -> Qimmat soliq hisob-kitobi bajarilmoqda...');
// Murakkab hisob-kitobni simulyatsiya qilish
for (let i = 0; i < 50000000; i++);
return (income * 0.2) + (region === 'EU' ? 100 : 50);
}
getTaxFor(income, region) {
return this.#calculateComplexTax(income, region);
}
}
const calculator = new FinanceCalculator();
console.log('Birinchi chaqiruv:');
calculator.getTaxFor(50000, 'EU');
console.log('\nIkkinchi chaqiruv (bir xil argumentlar):');
calculator.getTaxFor(50000, 'EU');
console.log('\nUchinchi chaqiruv (har xil argumentlar):');
calculator.getTaxFor(60000, 'NA');
// Konsol Chiqishi:
// Birinchi chaqiruv:
// [Memoize] #calculateComplexTax uchun yangi natija keshlanmoqda
// -> Qimmat soliq hisob-kitobi bajarilmoqda...
//
// Ikkinchi chaqiruv (bir xil argumentlar):
// [Memoize] #calculateComplexTax uchun keshdagi natija qaytarilmoqda
//
// Uchinchi chaqiruv (har xil argumentlar):
// [Memoize] #calculateComplexTax uchun yangi natija keshlanmoqda
// -> Qimmat soliq hisob-kitobi bajarilmoqda...
Qimmat hisob-kitob har bir noyob argumentlar to'plami uchun faqat bir marta qanday ishlashiga e'tibor bering. Ushbu qayta ishlatiladigan `@memoize` dekoratori endi dasturimizdagi har qanday sof xususiy metodni kuchaytirishi mumkin.
Amaliy Qo'llash 2: Ish Vaqtidagi Validatsiya va Tasdiqlashlar
Klassning ichki yaxlitligini ta'minlash juda muhim. Xususiy metodlar ko'pincha o'zlarining kirish ma'lumotlari to'g'ri holatda ekanligini taxmin qiladigan muhim operatsiyalarni bajaradi. Dekoratorlar ushbu taxminlarni yoki 'shartnomalarni' ish vaqtida amalga oshirishning elegant usulini taqdim etadi.
Misol: @validateInput bilan Kiruvchi Parametrlarni Validatsiya qilish
Keling, xususiy metodga uzatilgan argumentlarni tasdiqlash uchun dekorator fabrikasini — dekoratorni qaytaradigan funksiyani yarataylik. Buning uchun biz oddiy sxemadan foydalanamiz.
// Dekorator Fabrikasi: haqiqiy dekoratorni qaytaradigan funksiya
function validateInput(schemaValidator) {
return function(target, context) {
const methodName = context.name;
return function(...args) {
if (!schemaValidator(args)) {
throw new TypeError(`${methodName} xususiy metodi uchun noto'g'ri argumentlar.`);
}
const originalMethod = context.access.get(this);
return originalMethod.apply(this, args);
}
}
}
// Oddiy sxema validator funksiyasi
const userPayloadSchema = ([user]) => {
return typeof user === 'object' &&
user !== null &&
typeof user.id === 'string' &&
typeof user.email === 'string' &&
user.email.includes('@');
};
class UserAPI {
@validateInput(userPayloadSchema)
#createSavePayload(user) {
console.log('Yuklama to\'g\'ri, DB obyekti yaratilmoqda.');
return { db_id: user.id, contact_email: user.email };
}
saveUser(user) {
const payload = this.#createSavePayload(user);
// ... yuklamani ma'lumotlar bazasiga yuborish mantig'i
console.log('Foydalanuvchi muvaffaqiyatli saqlandi.');
}
}
const api = new UserAPI();
// To'g'ri chaqiruv
api.saveUser({ id: 'user-123', email: 'test@example.com' });
// Noto'g'ri chaqiruv
try {
api.saveUser({ id: 'user-456', email: 'invalid-email' });
} catch (e) {
console.error(e.message);
}
// Konsol Chiqishi:
// Yuklama to'g'ri, DB obyekti yaratilmoqda.
// Foydalanuvchi muvaffaqiyatli saqlandi.
// #createSavePayload xususiy metodi uchun noto'g'ri argumentlar.
Ushbu `@validateInput` dekoratori `#createSavePayload` shartnomasini aniq va o'z-o'zini majburlovchi qiladi. Asosiy metod mantig'i o'zining kirish ma'lumotlari har doim to'g'ri ekanligiga ishonch hosil qilib, toza qolishi mumkin. Ushbu naqsh katta, xalqaro jamoalarda ishlaganda juda kuchli, chunki u kutilmalarni to'g'ridan-to'g'ri kodda kodlaydi, bu esa xatolarni va tushunmovchiliklarni kamaytiradi.
Dekoratorlarni Zanjir qilish va Bajarilish Tartibi
Dekoratorlarning kuchi ularni birlashtirganda ortadi. Bitta metodga bir nechta dekorator qo'llashingiz mumkin va ularning bajarilish tartibini tushunish muhimdir.
Qoida shunday: Dekoratorlar pastdan yuqoriga baholanadi, lekin natijaviy funksiyalar yuqoridan pastga bajariladi.
Keling, buni oddiy log yozish dekoratorlari bilan ko'rsatamiz:
function A(target, context) {
console.log('Baholangan Dekorator A');
return function(...args) {
console.log('Bajarilgan O\'ram A - Boshlanish');
const original = context.access.get(this);
const result = original.apply(this, args);
console.log('Bajarilgan O\'ram A - Tugash');
return result;
}
}
function B(target, context) {
console.log('Baholangan Dekorator B');
return function(...args) {
console.log('Bajarilgan O\'ram B - Boshlanish');
const original = context.access.get(this);
const result = original.apply(this, args);
console.log('Bajarilgan O\'ram B - Tugash');
return result;
}
}
class Example {
@A
@B
#doWork() {
console.log(' -> Asosiy #doWork mantig\'i ishlamoqda...');
}
run() {
this.#doWork();
}
}
console.log('--- Klassni aniqlash ---');
const ex = new Example();
console.log('\n--- Metodni chaqirish ---');
ex.run();
// Konsol Chiqishi:
// --- Klassni aniqlash ---
// Baholangan Dekorator B
// Baholangan Dekorator A
//
// --- Metodni chaqirish ---
// Bajarilgan O'ram A - Boshlanish
// Bajarilgan O'ram B - Boshlanish
// -> Asosiy #doWork mantig'i ishlamoqda...
// Bajarilgan O'ram B - Tugash
// Bajarilgan O'ram A - Tugash
Ko'rib turganingizdek, klassni aniqlash paytida avval B dekoratori, keyin esa A baholandi. Metod chaqirilganda, A dan olingan o'ram funksiyasi birinchi bo'lib bajarildi, u keyin B dan olingan o'ramni chaqirdi, u esa nihoyat asl `#doWork` metodini chaqirdi. Bu sovg'ani bir necha qatlam qog'ozga o'rashga o'xshaydi; siz avval eng ichki qatlamni (B) qo'llaysiz, keyin keyingi qatlamni (A), lekin uni ochganingizda, avval eng tashqi qatlamni (A) olib tashlaysiz, keyin esa keyingisini (B).
Global Perspektiva: Nima uchun bu Zamonaviy Ishlab Chiqish uchun Muhim?
JavaScript xususiy metod dekoratorlari shunchaki sintaktik qulaylik emas; ular keng miqyosli, korporativ darajadagi ilovalarni yaratishda oldinga qo'yilgan muhim qadamni anglatadi. Nima uchun bu global ishlab chiqish hamjamiyati uchun muhim ekanligi:
- Yaxshilangan Qo'llab-quvvatlanuvchanlik: Vazifalarni ajratish orqali dekoratorlar kod bazalarini tushunishni osonlashtiradi. Tokiodagi dasturchi, ehtimol Berlindagi hamkasbi tomonidan yozilgan log yozish, keshlashtirish yoki validatsiya uchun shablon kodda adashmasdan metodning asosiy mantig'ini tushunishi mumkin.
- Kengaytirilgan Qayta Foydalanish Imkoniyati: Yaxshi yozilgan dekorator - bu yuqori darajada qayta ishlatiladigan kod qismidir. Bitta `@validate` yoki `@logExecutionTime` dekoratori yuzlab komponentlar bo'ylab import qilinishi va ishlatilishi mumkin, bu esa izchillikni ta'minlaydi va kod takrorlanishini kamaytiradi.
- Standartlashtirilgan Konvensiyalar: Katta, taqsimlangan jamoalarda dekoratorlar kodlash standartlari va arxitektura naqshlarini amalga oshirish uchun kuchli mexanizmni taqdim etadi. Yetakchi arxitektor autentifikatsiya, funksiya bayroqlari yoki xalqarolashtirish kabi masalalarni hal qilish uchun tasdiqlangan dekoratorlar to'plamini belgilashi mumkin, bu esa har bir dasturchi ushbu xususiyatlarni izchil, bashorat qilinadigan tarzda amalga oshirishini ta'minlaydi.
- Freymvork va Kutubxona Dizayni: Freymvorklar va kutubxonalar mualliflari uchun dekoratorlar toza, deklarativ API taqdim etadi. Bu kutubxona foydalanuvchilariga oddiy `@` sintaksisi bilan murakkab xulq-atvorlarni tanlash imkonini beradi, bu esa yanada intuitiv va yoqimli dasturchi tajribasiga olib keladi.
Xulosa: Klassga Asoslangan Dasturlashning Yangi Davri
JavaScript xususiy metod dekoratorlari klasslarning ichki xulq-atvorini kuchaytirishning xavfsiz va elegant usulini taqdim etadi. Ular dasturchilarga AOP, memoizatsiya va ish vaqtidagi validatsiya kabi kuchli naqshlarni inkapsulyatsiya va yagona mas'uliyatning asosiy tamoyillariga putur yetkazmasdan amalga oshirish imkonini beradi.
Kesishuvchi masalalarni qayta ishlatiladigan, deklarativ dekoratorlarga abstraktlash orqali biz nafaqat kuchliroq, balki o'qish, qo'llab-quvvatlash va kengaytirish uchun sezilarli darajada osonroq bo'lgan tizimlarni qurishimiz mumkin. Dekoratorlar JavaScript tilining tabiiy qismiga aylangan sari, ular shubhasiz, butun dunyodagi professional dasturchilar uchun ajralmas vositaga aylanadi va obyektga yo'naltirilgan va komponentga asoslangan dizaynda yangi darajadagi murakkablik va aniqlikni ta'minlaydi.
Ulardan bugun foydalanish uchun sizga hali ham Babel kabi vosita kerak bo'lishi mumkin bo'lsa-da, hozir bu o'zgartiruvchi xususiyatni o'rganish va tajriba qilish uchun eng zo'r vaqt. Toza, kuchli va qo'llab-quvvatlanadigan JavaScript klasslarining kelajagi shu yerda va u bezatilgan.