Module Pattern — Design Patterns

Module Pattern adalah cara mengorganisasi kode menjadi unit-unit mandiri dengan public dan private interface. Di JavaScript modern, ini sudah built-in lewat…

Module Pattern adalah cara membungkus kode jadi satu unit yang punya bagian privat, yang cuma bisa disentuh dari dalam, dan bagian publik, yang sengaja diserahkan ke luar. Bayangin loket ekspedisi. Pelanggan cuma bisa bicara lewat loket: "kirim paket", "cek resi". Buku catatan nomor resi ada di balik meja, dan pelanggan gak bisa mencoret angka di buku itu. Di kode, loketnya adalah object yang dikembalikan, dan buku catatannya adalah variabel yang disembunyikan di dalam function.

🧪 Tebakan cepat: Kurir Kancil membungkus counter resinya dalam function, menyimpan let count = 0 di dalamnya, dan cuma me-return { nextResi }. Setelah resi.nextResi() dipanggil dua kali, console.log(resi.count) mencetak apa? Tebak dulu, jawabannya ada di bagian "IIFE: modul dari closure".

Masalahnya: semua file berbagi satu ruang global

Di Kurir Kancil versi lama, tiap file dimuat dengan <script> biasa. Variabel var di level paling luar file seperti itu masuk ke satu ruang global yang sama untuk semua file. Dua file yang kebetulan memakai nama count sebenarnya memegang satu variabel yang sama:

// resi.js
var count = 0
function nextResi() {
  count = count + 1
  return "KCL-" + String(count).padStart(4, "0")
}

// promo.js (ditulis orang lain, untuk kuota promo harian)
var count = 0
function resetPromo() {
  count = 0 // maksudnya cuma mereset kuota promo
}

// main.js
console.log(nextResi()) // KCL-0001
resetPromo()
console.log(nextResi()) // KCL-0001 lagi!

resetPromo mengenolkan count milik resi juga, jadi dua paket mendapat nomor resi KCL-0001. Gak ada error, cuma dua paket yang tertukar di gudang.

IIFE: modul dari closure

Sebelum JavaScript punya import dan export, cara membuat ruang privat adalah function. Variabel yang dibuat di dalam function gak bisa disentuh dari luar function itu:

const resi = (function () {
  let count = 0 // privat: cuma fungsi di dalam sini yang bisa menyentuhnya

  function nextResi() {
    count = count + 1
    return "KCL-" + String(count).padStart(4, "0")
  }

  return { nextResi } // publik: hanya ini yang diserahkan ke luar
})()

console.log(resi.nextResi()) // KCL-0001
console.log(resi.nextResi()) // KCL-0002
console.log(resi.count)      // undefined

Bentuk "tulis semua function di dalam, lalu return object yang menyebut yang mau dibuka" punya nama sendiri: Revealing Module Pattern. Kalau promo.js dibungkus dengan cara yang sama, count miliknya jadi variabel lain, dan resetPromo() gak bisa lagi mengganggu resi.

ES module: pattern yang sudah jadi fitur bahasa

JavaScript modern punya module bawaan. Tiap file module punya ruang sendiri: variabel di level paling luar file itu privat, dan yang bisa dipakai file lain cuma yang di-export.

// resi.js
let count = 0 // gak di-export, jadi cuma file ini yang bisa menyentuhnya

export function nextResi() {
  count = count + 1
  return "KCL-" + String(count).padStart(4, "0")
}

// main.js
import { nextResi } from "./resi.js"

console.log(nextResi()) // KCL-0001

Playground di halaman ini menjalankan satu script, bukan beberapa file, jadi contoh yang bisa kamu jalankan di sana memakai bentuk IIFE.

Kapan gak perlu dibungkus

⚠️ Jebakan yang sering ketemu

TL;DR: Module Pattern membungkus kode dalam scope privat dan hanya mengekspos bagian yang diperlukan. Bentuk lamanya IIFE: (function () { let count = 0; return { nextResi } })(), function yang langsung dipanggil sekali, dengan count aman di dalam closure dan resi.count bernilai undefined. Bentuk modernnya ES module: variabel di level paling luar file itu privat, yang publik cuma yang di-export, dan module dijalankan sekali. Masalah yang dihilangkan: variabel global yang saling menimpa, seperti resetPromo() yang membuat resi KCL-0001 keluar dua kali. Jangan lupa () di ujung IIFE, dan serahkan function, bukan salinan angka.

Yang akan kamu pelajari