Belajar JavaScript - Scope, Closure, dan Konteks this
Episode 12 of 23

Belajar JavaScript - Scope, Closure, dan Konteks this

Episode ini menuntaskan tiga konsep tersulit di JavaScript: rantai scope yang menentukan visibilitas variabel, closure yang membuat fungsi mengingat lingkungan lahirnya, dan empat aturan binding this beserta call, apply, serta bind. Ini fondasi untuk memahami kode produksi yang kompleks.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Episode 12 adalah puncak fase dua — tiga konsep yang saling terkait dan sering dianggap paling membingungkan di JavaScript: scope, closure, dan this. Di episode 4 kalian sudah melihat scope global, function, dan block secara singkat. Sekarang kita memperdalamnya: bagaimana rantai scope bekerja, mekanisme closure yang menjadi dasar banyak pola produksi, dan empat aturan binding this.

Mengapa tiga hal ini dibahas bersama? Karena semuanya tentang satu pertanyaan: saat kode berjalan, nilai atau variabel apa yang bisa diakses dari titik itu? Scope menjawab untuk variabel, closure mengeksploitasi jawaban itu, dan this menjawab untuk objek yang sedang aktif. Tiga konsep ini sering muncul di interview kerja, jadi pahami mekanismenya, bukan hafalannya.

Scope dan Rantai Scope

Lexical Scope

Scope ditentukan saat kode ditulis, bukan saat dieksekusi — inilah arti lexical. Fungsi di dalam fungsi bisa mengakses variabel scope luarnya, tapi tidak sebaliknya:

JSRantai scope
const nama = "Global";
 
function luar() {
  const namaLuar = "Di fungsi luar";
 
  function dalam() {
    const namaDalam = "Di fungsi dalam";
    console.log(nama);
    console.log(namaLuar);
    console.log(namaDalam);
  }
 
  dalam();
}
 
luar();

dalam bisa mengakses namaLuar dari luar dan nama dari global — ini rantai scope (scope chain). Setiap fungsi menambah satu lapisan ke atas mencari variabel. Sebaliknya, luar tidak bisa mengakses namaDalam milik dalam, dan global tidak bisa mengakses keduanya. Pencarian selalu naik, tidak pernah turun.

Closure

Fungsi yang Mengingat Lingkungannya

Closure terjadi ketika sebuah fungsi "membawa" variabel dari scope lahirnya, bahkan setelah scope itu selesai dieksekusi:

JSClosure paling dasar
function buatPenghitung() {
  let hitung = 0;
 
  return function () {
    hitung += 1;
    return hitung;
  };
}
 
const counter = buatPenghitung();
 
console.log(counter());
console.log(counter());
console.log(counter());

buatPenghitung mengembalikan fungsi yang menambah hitung. Normalnya hitung mati setelah buatPenghitung selesai — tapi karena fungsi dalam menutup (closure) atasnya, hitung tetap hidup. Setiap pemanggilan counter() menghasilkan 1, 2, 3. Inilah mekanisme private state di JavaScript, dan dasar dari pola function factory di episode 8.

Jebakan Closure dalam Loop

Jebakan klasik: membuat closure di dalam loop dengan var. Solusi modern adalah let, yang membuat variabel per iterasi:

JSClosure dan let di dalam loop
for (let i = 1; i <= 3; i++) {
  setTimeout(() => {
    console.log(i);
  }, 100);
}

let memberi i cakupan per iterasi, sehingga setiap callback menutup nilai yang berbeda: 1, 2, 3. Jika diganti var, semua callback menutup variabel yang sama dan semuanya mencetak 4. Ini alasan utama let menggantikan var di kode modern.

Konteks this: Empat Aturan Binding

Default Binding dan Implicit Binding

this di function biasa ditentukan oleh cara fungsi dipanggil. Empat aturannya:

  • Default binding: this menunjuk ke global (atau undefined di strict mode) saat fungsi dipanggil berdiri sendiri.
  • Implicit binding: this menunjuk ke objek di depan tanda titik saat fungsi dipanggil sebagai method.
  • Explicit binding: dipaksa lewat call, apply, atau bind.
  • New binding: dipaksa lewat operator new.
JSImplicit binding
const pengguna = {
  nama: "Arman",
  panggil: function () {
    console.log(this.nama);
  },
};
 
pengguna.panggil();

pengguna.panggil() memakai implicit binding: karena dipanggil lewat pengguna, this menunjuk ke pengguna, sehingga hasilnya "Arman". Jika fungsinya dipisah dan dipanggil berdiri sendiri, this tidak lagi menunjuk ke pengguna.

Arrow Function Tidak Punya this Sendiri

Arrow function tidak punya this sendiri — dia mewarisi this dari scope terdekat yang memilikinya:

JSArrow function mewarisi this
const tim = {
  nama: "Squad Dev",
  anggota: ["Arman", "Sari"],
  perkenalan: function () {
    this.anggota.forEach((nama) => {
      console.log(`${nama} dari ${this.nama}`);
    });
  },
};
 
tim.perkenalan();

perkenalan adalah function biasa sehingga this menunjuk ke tim. Arrow function di dalamnya mewarisi this tersebut — bukan membuat miliknya sendiri — sehingga this.nama tetap "Squad Dev". Kalau diganti function biasa, this di dalam callback akan lepas dari tim.

Mengendalikan this dengan call, apply, dan bind

call dan apply: Memanggil dengan this Tertentu

call dan apply memanggil fungsi segera dengan this yang kalian tentukan. Bedanya hanya di cara mengirim argumen: call satu per satu, apply lewat array:

JScall dan apply
function perkenalkan(kota, tahun) {
  console.log(`${this.nama} dari ${kota}, sejak ${tahun}`);
}
 
const arman = { nama: "Arman" };
 
perkenalkan.call(arman, "Jakarta", 2020);
perkenalkan.apply(arman, ["Jakarta", 2020]);

perkenalkan.call(arman, "Jakarta", 2020) dan versi apply dengan array menghasilkan output yang sama. Di sini this dipaksa menunjuk ke arman meskipun perkenalkan bukan method arman.

bind: Menciptakan Fungsi Baru dengan this Tetap

Berbeda dari call dan apply yang langsung memanggil, bind membuat fungsi baru dengan this yang terkunci:

JSbind mengunci this
const pengguna = {
  nama: "Arman",
  sapaan: function () {
    return `Halo, ${this.nama}`;
  },
};
 
const ambilSapaan = pengguna.sapaan;
const ambilSapaanKunci = pengguna.sapaan.bind(pengguna);
 
console.log(ambilSapaanKunci());

ambilSapaan yang dipanggil berdiri sendiri kehilangan this — tapi ambilSapaanKunci yang dibuat dengan .bind(pengguna) selalu menunjuk ke pengguna apa pun cara memanggilnya. bind adalah solusi klasik ketika sebuah method dilepas dari objeknya, misalnya dikirim sebagai callback.

Penutup

Episode 12 menuntaskan tiga konsep tersulit: rantai scope yang menentukan visibilitas variabel secara lexical, closure yang membuat fungsi mengingat lingkungan lahirnya dengan state privat, dan empat aturan binding this plus call, apply, serta bind untuk mengendalikannya.

Inti yang harus dibawa pulang:

  • Scope bersifat lexical: ditentukan saat kode ditulis, dan pencarian selalu naik.
  • Closure membuat fungsi mengingat variabel dari scope lahirnya.
  • let di loop memberi closure nilai per iterasi; var tidak.
  • this ditentukan oleh cara fungsi dipanggil, bukan tempat ditulis.
  • Arrow function tidak punya this sendiri; dia mewarisi dari atas.
  • call dan apply memanggil langsung; bind membuat fungsi baru yang terkunci.

Di episode 13 selanjutnya kita masuk ke fase tiga: DOM API dan manipulasi elemen — memilih elemen dengan selector, mengubah konten dan style, membuat elemen baru, serta mengelola class dan atribut. Inilah saat JavaScript mulai berinteraksi dengan halaman web sungguhan.

Belajar JavaScript - Scope, Closure, dan Konteks this | Belajar JavaScript