Menu

Kata Kunci this di JavaScript: Aturan Binding dan Jebakannya

Cara kerja this yang sebenarnya di JavaScript: empat aturan binding, kenapa arrow function berbeda, dan cara menghindari jebakan klasik 'this is undefined'.

Halaman ini dilengkapi editor yang bisa dijalankan. Edit, jalankan, dan lihat output-nya seketika.

this ditentukan saat pemanggilan

Sebagian besar kebingungan soal this berasal dari satu asumsi keliru: bahwa this bergantung pada tempat fungsi didefinisikan. Tidak. this bergantung pada cara fungsi itu dipanggil.

Lihat fungsi yang sama dipanggil dengan dua cara:

Fungsinya sama, this-nya berbeda. Pemanggilan pertama punya user di kiri titik, jadi this adalah user. Pemanggilan kedua tidak punya apa-apa di kiri, jadi this bernilai undefined. Fungsinya sendiri tidak berubah; tempat pemanggilannyalah yang berubah.

Ingat ide itu: untuk mengetahui this, lihat pemanggilannya, bukan definisinya.

Empat aturan binding

Ada empat cara this diatur. Hampir setiap pertanyaan seputar this yang akan kamu punya terjawab dengan mengetahui aturan mana yang berlaku.

1. Pemanggilan method: obj.fn()

Saat sebuah fungsi dipanggil sebagai property dari sebuah object, this adalah object itu:

Apa yang ada di kiri titik menjadi this. Sesederhana itu.

2. Pemanggilan biasa: fn()

Kalau dipanggil tanpa object di depannya, this bernilai undefined di strict mode (yang otomatis menyala di module dan class) atau object global di sloppy mode:

Dari sinilah error "this is undefined" berasal. Melepas method dari object-nya mengubah pemanggilan method menjadi pemanggilan biasa:

Tidak ada counter. sebelum pemanggilan, tidak ada binding. Fungsinya tidak ingat dari object mana ia berasal.

3. Binding eksplisit: .call(), .apply(), .bind()

Kamu bisa memaksa this menjadi apa pun yang kamu mau:

.call dan .apply langsung memanggil fungsinya; bedanya hanya pada cara argumen dikirim. .bind mengembalikan fungsi baru dengan this yang terkunci permanen, berguna untuk callback.

4. Pemanggilan dengan new: new Fn()

Memanggil fungsi dengan new membuat object baru dan mengikatnya ke this:

Class memakai mekanisme ini di balik layar. Kita akan bertemu class di bab berikutnya.

Arrow function tidak punya this sendiri

Arrow function melanggar aturan-aturan di atas, dengan sengaja. Ia sama sekali tidak mengikat this: ia mewarisinya dari scope di sekitarnya, dibekukan pada saat arrow itu didefinisikan:

Arrow di tingkat teratas module menangkap this milik module, yaitu undefined. Walaupun ia dipanggil sebagai user.arrow(), arrow menolak diikat ulang.

Kedengarannya seperti bug, tapi justru itulah intinya. Arrow function unggul di dalam method, saat kamu ingin mempertahankan this dari luar:

Arrow di dalam setInterval mewarisi this dari start, yang dipanggil sebagai timer.start(). Jadi this.seconds berfungsi. function biasa di situ akan mendapat this miliknya sendiri (apa pun yang dikirim setInterval) dan rusak.

Patokannya: pakai arrow function untuk callback di dalam method. Pakai fungsi biasa untuk method itu sendiri.

Jebakan callback klasik

Inilah cara paling umum this jadi kacau. Kamu mengirim sebuah method sebagai callback, dan ia kehilangan binding-nya:

setTimeout memanggil fungsinya sebagai pemanggilan biasa, bukan sebagai c.increment(). Ada tiga cara memperbaikinya:

Ketiganya berhasil. Pembungkus arrow biasanya yang paling jelas.

this di tingkat teratas

this di tingkat teratas bergantung pada tempat kodemu berjalan:

  • Script browser (bukan module): this adalah window.
  • ES module (termasuk sebagian besar kode modern hasil bundling): this bernilai undefined.
  • Module CommonJS Node.js: this adalah module.exports.

Untuk rujukan yang andal ke object global di semua lingkungan, pakai globalThis:

Dalam praktiknya, sebaiknya kamu tidak mengandalkan this di tingkat teratas. Pakai globalThis saat kamu memang butuh object global, dan selebihnya kirim nilai secara eksplisit.

Pohon keputusan singkat

Saat kamu melihat this dan tidak yakin nilainya apa, telusuri daftar ini:

  1. Apakah fungsinya arrow function? Kalau ya, this adalah apa pun nilainya di scope yang membungkusnya. Abaikan tempat pemanggilan sepenuhnya.
  2. Apakah dipanggil dengan new? Kalau ya, this adalah object baru itu.
  3. Apakah dipanggil dengan .call, .apply, atau fungsi hasil bind? Kalau ya, this adalah apa yang dikirim.
  4. Apakah dipanggil sebagai obj.method()? Kalau ya, this adalah obj.
  5. Apakah dipanggil sebagai fn() biasa? Kalau ya, this bernilai undefined di strict mode.

Tangga itu, dengan urutan itu, menentukan setiap kasus.

Berikutnya: higher-order function

Sekarang this bukan lagi misteri, kamu siap untuk pola yang membuat JavaScript begitu ekspresif: mengoper fungsi sebagai nilai. Selanjutnya kita akan melihat higher-order function, yaitu fungsi yang menerima atau mengembalikan fungsi lain, dan bagaimana fungsi itu menggerakkan method array, event handler, dan sebagian besar kode JavaScript di dunia nyata.

Pertanyaan yang sering diajukan

this merujuk ke apa di JavaScript?

this merujuk ke object tempat sebuah fungsi dipanggil, bukan tempat fungsi itu didefinisikan. Di user.greet(), this adalah user. Di pemanggilan greet() biasa, this bernilai undefined di strict mode (atau object global di sloppy mode). Aturannya tentang tempat pemanggilan, bukan tempat definisi.

Kenapa this bernilai undefined di dalam fungsiku?

Kemungkinan kamu melepas sebuah method dari object-nya lalu memanggilnya sendirian, atau mengirimnya sebagai callback. const fn = user.greet; fn(); kehilangan binding-nya: tidak ada object di kiri titik di tempat pemanggilan. Perbaiki dengan .bind(user), pembungkus arrow function, atau dengan memanggilnya sebagai user.greet().

Apa bedanya this di arrow function?

Arrow function tidak punya this sendiri. Ia mewarisinya dari scope di sekitarnya pada saat ia didefinisikan. Karena itu arrow function ideal untuk callback di dalam method, saat kamu ingin mempertahankan this dari luar. Ini juga berarti .call(), .apply(), dan .bind() tidak bisa mengubah this untuk arrow function.

Apa nilai this di tingkat teratas script?

Di script biasa di browser, this di tingkat teratas adalah object window. Di ES module, nilainya undefined. Di module CommonJS Node.js, nilainya module.exports. Rujukan yang berlaku di semua lingkungan adalah globalThis, yang selalu menunjuk ke object global.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai