Module Pattern
ES Modules'dan oldin JS'da built-in modul tizimi yo'qligi, IIFE + closure orqali qo'lda private/public ajratish, Revealing Module Pattern, va bu yondashuvning dependency boshqaruvi/global namespace kabi hal qilinmagan muammolari.
72-dars
Module Pattern
ES Modules paydo bo'lishidan oldin (va hozir ham ba'zi joylarda), JavaScript'da hech qanday built-in modul tizimi yo'q edi. Butun dastur bitta global scope'da ishlar edi:
var count = 0;
function increment() { count++; }
Agar loyihada 10 ta <script> fayli bo'lsa, ularning hammasi bitta global obyektga (window) yozadi. Ikkita fayl tasodifan bir xil nom ishlatsa — biri ikkinchisini ustidan bosib yozib yuboradi (global namespace pollution). Bundan tashqari, "bu o'zgaruvchi private, tashqaridan tegilmasin" degan mexanizm umuman yo'q edi.
Module Pattern — shu muammoni til darajasida yechim kelmasdan oldin, dasturchilar closure yordamida qo'lda hal qilgan usuli.
1. Qanday ishlaydi — IIFE + Closure
const CounterModule = (function () {
// bu yerdagilar — PRIVATE, tashqaridan ko'rinmaydi
let count = 0;
function log(msg) {
console.log(`[Counter]: ${msg}`);
}
// faqat shu qaytarilganlar — PUBLIC API
return {
increment() {
count++;
log(`count = ${count}`);
},
reset() {
count = 0;
},
getCount() {
return count;
}
};
})();
CounterModule.increment(); // [Counter]: count = 1
console.log(CounterModule.count); // undefined — tashqaridan ko'rinmaydi!
Bu yerda nima sodir bo'lyapti:
(function(){...})()— IIFE (Immediately Invoked Function Expression) darrov chaqiriladi va o'z scope'ini yaratadi.countvalogshu scope ichida qoladi — tashqi dunyo ularga hech qanday yo'l bilan to'g'ridan-to'g'ri kira olmaydi.- Qaytarilgan obyekt (
{ increment, reset, getCount }) — bu public interfeys. Lekin bu metodlar closure orqalicountga bog'langan bo'lib qoladi.
Bu yerda avvalda o'tgan closure tushunchasi qayta ishga tushyapti — funksiya o'zi yaratilgan lexical muhitni "eslab qoladi", shuning uchun increment chaqirilganda u haligacha o'sha countga yeta oladi, garchi IIFE allaqachon ishlab bo'lgan (execution context stack'dan chiqib ketgan) bo'lsa ham.
2. Revealing Module Pattern (biroz yaxshilangan variant)
const CounterModule = (function () {
let count = 0;
function increment() {
count++;
}
function reset() {
count = 0;
}
function getCount() {
return count;
}
// Barcha funksiyalar avval TO'LIQ e'lon qilinadi,
// keyin faqat kerakli qismi "reveal" qilinadi (ochiladi)
return { increment, reset, getCount };
})();
Farqi: yuqoridagi versiyada obyekt literal ichida to'g'ridan-to'g'ri metod yozilgan edi, bu yerda esa avval oddiy funksiyalar sifatida yozib, oxirida faqat kerakli nomlarni qaytaramiz — bu o'qilishi osonroq va qaysi funksiya public, qaysi private ekanini bir joyda ko'rish qulayroq.
3. Bu yerda qanday muammolar qolgan edi?
- Modullar orasida bog'liqlik (dependency) boshqarish qiyin — agar Module B, Module A'ga muhtoj bo'lsa, ularni to'g'ri tartibda yuklash dasturchining zimmasida (
<script>teglar tartibi orqali). - Bitta fayl = bitta global nom muammosi hali ham bor edi (
CounterModule— bu ham aslida global). - Static analiz (masalan, "bu modul nimalarni ishlatyapti" deb avvaldan bilish) imkonsiz — chunki hammasi runtime'da, oddiy funksiya chaqiruvi orqali ishlaydi.
Bu muammolar keyinchalik CommonJS (Node.js uchun) va ES Modules (brauzer + zamonaviy standart) orqali hal qilindi — ularni keyingi bandlarda ko'ramiz.