Mixin pattern
Muammodan boshlaylik
Dasturda ikki xil turdagi ob'ekt bor: Foydalanuvchi va Mahsulot. Ular bir-biriga aloqasi yo'q.
Lekin ikkalasida ham bir xil narsa kerak: harakatlarni jurnalga yozish. Foydalanuvchi tizimga kirdi — yozilsin. Mahsulot ko'rildi — yozilsin.
extends bilan yechishga urindingiz:
class Foydalanuvchi extends Jurnal { ... }
class Mahsulot extends Jurnal { ... }
Ishlaydi. Lekin keyinchalik Foydalanuvchi ga yana bir narsa kerak bo'ldi — Serializatsiya. extends bilan ikkita ota class bo'lmaydi:
class Foydalanuvchi extends Jurnal, Serializatsiya { } // ❌ — JavaScript da bunday bo'lmaydi
JavaScript da bitta classdan meros olish mumkin. Bu — yagona meros (single inheritance) cheklovi.
Mixin — bu cheklovni aylanib o'tishning yo'li.
Mixin nima?
Mixin — classga meros olmay turib, tayyor metodlar "to'plamini" qo'shish usuli.
Hayotiy o'xshatma
Ko'ylak va shim — ikki xil kiyim. Lekin ikkalasiga ham bir xil narsa qo'shish mumkin: "issiqlatuvchi" yostiq. Issiqlatuvchi — na ko'ylak, na shim. U faqat "qo'shimcha imkoniyat". Xohlagan kiyimga tikib qo'yiladi.
Mixin — o'sha "qo'shimcha qism". U classning o'zi emas — faqat metodlar to'plami. Istalgan classga qo'shib beriladi, meros olmay.
Eng oddiy mixin
Mixin — metodlar yozilgan oddiy ob'ekt. Uni classning prototype iga qo'shish — barcha ob'ektlar o'sha metodlarga ega bo'ladi.
// Mixin — oddiy ob'ekt, metodlar to'plami
const JurnalMixin = {
log(xabar) {
const vaqt = new Date().toLocaleTimeString();
console.log(`[${vaqt}] ${this.constructor.name}: ${xabar}`);
}
};
Bu metodda this bor — lekin this hali noaniq. U qaysi classga qo'shilsa, o'sha classning ob'ektini ko'rsatadi. Mixin yozilayotganda this kim bo'lishi muhim emas — qo'shilganda aniqlanadi.
class Foydalanuvchi {
constructor(ism) {
this.ism = ism;
}
}
class Mahsulot {
constructor(nomi) {
this.nomi = nomi;
}
}
// Ikkala classga bir xil mixin qo'shildi
Object.assign(Foydalanuvchi.prototype, JurnalMixin);
Object.assign(Mahsulot.prototype, JurnalMixin);
const jasur = new Foydalanuvchi("Jasur");
const noutbuk = new Mahsulot("Noutbuk");
jasur.log("Tizimga kirdi");
// "[10:32:15] Foydalanuvchi: Tizimga kirdi"
noutbuk.log("Ko'rildi");
// "[10:32:17] Mahsulot: Ko'rildi"
Nima uchun Object.assign(prototype, mixin)?
prototype ga qo'shilganda — barcha keyingi ob'ektlar ham metodga ega bo'ladi. Agar to'g'ridan Foydalanuvchi.log = ... qilinsa — bu static metod bo'lib qolardi, ob'ektlarni ko'ra olmasdi.
Bir nechta mixin
Bitta classga bir nechta mixin qo'shish mumkin:
const JurnalMixin = {
log(xabar) {
console.log(`[LOG] ${this.constructor.name}: ${xabar}`);
}
};
const ValidationMixin = {
tekshir(maydon, qiymat) {
if (!qiymat || qiymat.toString().trim() === "") {
throw new Error(`${maydon} bo'sh bo'lmasligi kerak`);
}
return true;
}
};
class Foydalanuvchi {
constructor(ism, email) {
this.tekshir("ism", ism); // ValidationMixin dan
this.tekshir("email", email); // ValidationMixin dan
this.ism = ism;
this.email = email;
this.log("Yaratildi"); // JurnalMixin dan
}
}
// Ikkala mixin bir vaqtda qo'shildi
Object.assign(Foydalanuvchi.prototype, JurnalMixin, ValidationMixin);
const jasur = new Foydalanuvchi("Jasur", "jasur@mail.com");
// "[LOG] Foydalanuvchi: Yaratildi"
new Foydalanuvchi("", "jasur@mail.com");
// ❌ Error: ism bo'sh bo'lmasligi kerak
Mixin va extends — qachon qaysi?
Bu savol tez-tez chiqadi. Oddiy qoida:
extends — "bu nima?" savoliga javob bersa. Admin — Foydalanuvchi. Mushuk — Hayvon. Bir narsa boshqasining turi.
Mixin — "bu nima qila oladi?" savoliga javob bersa. Foydalanuvchi jurnal yoza oladi. Mahsulot ham jurnal yoza oladi. Tur emas — qobiliyat.
Admin extends Foydalanuvchi ✅ — Admin IS A Foydalanuvchi
Foydalanuvchi + JurnalMixin ✅ — Foydalanuvchi CAN log
Tez-tez uchraydigan xatolar
Mixin ichida arrow function ishlatish:
Mixin metodlarida this muhim — u qaysi ob'ektga qo'shilganini ko'rsatishi kerak. Arrow function esa this ni tashqaridan oladi — mixin yozilgan joydan. Bu noto'g'ri ishlaydi.
// ❌ — arrow function, this noto'g'ri
const Mixin = {
log: () => {
console.log(this.ism); // undefined — this = global yoki undefined
}
};
// ✅ — oddiy funksiya, this = chaqiruvchi ob'ekt
const Mixin = {
log() {
console.log(this.ism); // ✅
}
};
Mixin classning mavjud metodini yozib ketishi:
class Foydalanuvchi {
info() { return `Foydalanuvchi: ${this.ism}`; }
}
const Mixin = {
info() { return "Mixin info"; } // ← Foydalanuvchi.info ni yozib ketadi!
};
Object.assign(Foydalanuvchi.prototype, Mixin);
new Foydalanuvchi("Jasur").info(); // "Mixin info" ← kutilmagan natija
Mixin qo'shishdan oldin method nomlarining to'qnashmasligi tekshirilishi kerak.
Xulosa
Mixin — classga meros olmay turib metodlar qo'shish usuli. Object.assign(Class.prototype, mixin) orqali.
JavaScript da bitta classdan meros olish mumkin — mixin bu cheklovni yechadi. Bir nechta "qobiliyat to'plami"ni istalgan classga qo'shish mumkin.
extends — "bu nima" (IS-A munosabat). Mixin — "bu nima qila oladi" (CAN-DO qobiliyat).
Keyingi dars
34-dars: Sinxron va Asinxron — farqi va nima uchun kerak