Seriya: JavaScript Basics Dars 72

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:

  1. (function(){...})() — IIFE (Immediately Invoked Function Expression) darrov chaqiriladi va o'z scope'ini yaratadi.
  2. count va log shu scope ichida qoladi — tashqi dunyo ularga hech qanday yo'l bilan to'g'ridan-to'g'ri kira olmaydi.
  3. Qaytarilgan obyekt ({ increment, reset, getCount }) — bu public interfeys. Lekin bu metodlar closure orqali countga 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.