Dekoratorlar va uzatish, call/apply
JavaScript funksiyalar bilan ishlashda ajoyib moslashuvchanlik beradi. Ularni uzatish, o'ram (wrapper) bilan qoplash mumkin. Ushbu darsda dekoratorlar va kontekstni uzatuvchi call/apply metodlarini o'rganamiz.
Dekorator nima?
Dekorator โ bu funksiyani argument sifatida oladigan va uning xatti-harakatini o'zgartiruvchi yangi funksiyani qaytaradigan funksiya. Asl funksiya o'zgarmaydi โ uning atrofiga qo'shimcha imkoniyat "o'raladi".
Masalan, sekin ishlaydigan funksiyaning natijalarini keshlab (eslab) qo'yadigan dekorator yozamiz:
sekinHisob funksiyasi o'zgarmadi. Biz uni tashqaridan "kesh" imkoniyati bilan qopladik. Bu โ vazifalarni ajratish (separation of concerns) tamoyilining yaxshi namunasi.Kontekst muammosi
Yuqoridagi keshlovchi oddiy funksiyalar uchun ishlaydi. Ammo obyekt metodlari bilan muammo chiqadi. Metod ichida this ishlatilsa, dekorator uni func(x) deb chaqirganda this yo'qoladi:
let ishchi = {
narx: 1000,
sekinHisob(x) {
return x * this.narx; // this KERAK
}
};
// keshlovchi ichida func(x) deb chaqirilsa, this yo'qoladi
// va "Cannot read property 'narx' of undefined" xatoligi chiqadi
Buni hal qilish uchun bizga thisni to'g'ri uzatish yo'li kerak. Aynan shu yerda call yordamga keladi.
func.call โ kontekstni aniq uzatish
func.call(context, arg1, arg2, ...) funksiyani chaqiradi, lekin thisni birinchi argument sifatida aniq belgilaydi:
func.call(obj) โ bu deyarli obj.func() bilan bir xil, lekin thisni aniq belgilaydi. Argumentlarni ham ketma-ket uzatish mumkin:
func.apply โ argumentlarni massiv bilan
func.apply call bilan deyarli bir xil, lekin argumentlarni massiv ko'rinishida qabul qiladi:
func.call(context, arg1, arg2, arg3);
func.apply(context, [arg1, arg2, arg3]); // xuddi shu natija
func.call(ctx, ...args)) applyga muqobil hisoblanadi. Ammo apply ba'zan bir oz tezroq (dvigatel uni yaxshi optimallashtiradi) va eski kodda ko'p uchraydi.Chaqiruvni uzatish (call forwarding)
Dekoratorlarda ko'pincha barcha argumentlarni va kontekstni asl funksiyaga to'liq uzatish kerak bo'ladi. Buning uchun func.apply(this, arguments) naqshi ishlatiladi:
func.apply(this, arguments) โ bu chaqiruvni uzatish (call forwarding). U tashqi o'ramning thisini va barcha argumentlarini asl funksiyaga to'liq "o'tkazib yuboradi", go'yo o'ram umuman bo'lmagandek.
arguments โ bu massivsimon obyekt (array-like), haqiqiy massiv emas. Uni applyga to'g'ridan-to'g'ri berish mumkin, lekin massiv metodlarini (masalan .map) ishlatish uchun Array.from(arguments) yoki [...arguments] orqali massivga o'girish kerak.Metodni "qarzga olish" (method borrowing)
call/applyning yana bir foydali qo'llanishi โ bir obyektning metodini boshqa obyektda ishlatish. Masalan, arguments massivsimon obyektida massivning join metodini ishlatish:
Xulosa
- Dekorator โ funksiyani o'rab, uning xatti-harakatini o'zgartiradigan funksiya (masalan, keshlovchi);
func.call(ctx, arg1, arg2...)โthisva argumentlarni birma-bir uzatib chaqiradi;func.apply(ctx, argsMassiv)โ argumentlarni massiv sifatida uzatadi;func.apply(this, arguments)โ dekoratorlarda chaqiruvni to'liq uzatish uchun ishlatiladi;call/applymetodni boshqa obyektga "qarzga berish"ga ham imkon beradi.