Arrow function tidak memiliki this sendiri, sehingga kata this di dalam tubuhnya diambil dari lingkup di sekitarnya. Perilaku ini disebut this leksikal, yaitu this yang ditentukan oleh tempat penulisan fungsi, bukan oleh call-site-nya, kebalikan dari aturan pada topik Dasar this. Topik ini membuktikan perilaku itu pada metode dan callback, memperagakannya pada event handler browser melalui demo, lalu menutup dengan keadaan ketika arrow justru menjadi pilihan keliru. Semua contoh berupa berkas JavaScript utuh yang dijalankan dengan Node.js, kecuali demo browsernya.
Arrow memakai this lingkup luarnya#
Arrow function tidak membuat this sendiri, dan pencarian this di dalamnya berjalan seperti pencarian variabel biasa, yaitu naik ke lingkup leksikal di luarnya. Bila arrow ditulis di dalam sebuah metode, this di dalam arrow adalah this milik metode itu. Mekanisme ini disebut this leksikal karena hasilnya ditentukan saat kode ditulis, bukan saat pemanggilan terjadi. Perbandingan langsung terlihat pada satu metode yang memuat dua fungsi kecil, satu arrow dan satu fungsi biasa.
// Arrow tidak punya this sendiri dan memakai this lingkup luarnya.
const kursus = {
nama: "Kursus JavaScript",
pasang() {
const denganArrow = () => "arrow, this.nama: " + this.nama;
const denganFungsi = function () {
return "fungsi biasa, this.nama: " + this.nama;
};
return denganArrow() + " | " + denganFungsi();
}
};
console.log(kursus.pasang());arrow, this.nama: Kursus JavaScript | fungsi biasa, this.nama: undefinedArrow denganArrow ditulis di dalam metode pasang, sehingga this-nya adalah this milik pasang, yaitu kursus, dan nama kursusnya terbaca. Fungsi biasa denganFungsi membuat this sendiri, dan karena dipanggil lepas lewat denganFungsi(), this-nya menjadi globalThis pada Node.js, sehingga this.nama menghasilkan undefined. Perbedaannya murni pada cara pencarian this, sedangkan letak kedua fungsi di dalam metode yang sama persis.
Callback yang kehilangan this dan perbaikannya#
Pola yang sama muncul pada callback, fungsi yang dioper kepada fungsi lain untuk dipanggil kembali. Bila callback ditulis sebagai fungsi biasa, call-site-nya berada di tangan penerima callback, dan this-nya mengikuti bentuk pemanggilan di sana, sering kali panggilan lepas. Bila callback ditulis sebagai arrow, this-nya diambil dari metode yang menuliskannya. Berkas berikut mengoper dua versi callback yang sama kepada object tombol.
// Callback fungsi biasa kehilangan this, versi arrow mempertahankannya.
const tombol = {
label: "Simpan",
tekan(callback) {
callback();
}
};
const aplikasi = {
nama: "Editor Catatan",
pasangDenganFungsiBiasa() {
tombol.tekan(function () {
console.log("fungsi biasa, this.nama:", this.nama);
});
},
pasangDenganArrow() {
tombol.tekan(() => {
console.log("arrow, this.nama:", this.nama);
});
}
};
aplikasi.pasangDenganFungsiBiasa();
aplikasi.pasangDenganArrow();fungsi biasa, this.nama: undefined
arrow, this.nama: Editor CatatanObject tombol memanggil callback lepas lewat callback(), tanpa titik dan tanpa penerima. Callback fungsi biasa membuat this sendiri sehingga isinya globalThis, dan this.nama tidak menemukan apa pun. Callback arrow tidak membuat this sendiri, this-nya diambil dari metode pasangDenganArrow yang memang dipanggil lewat aplikasi, sehingga nama aplikasinya terbaca. Inilah alasan arrow memperbaiki banyak callback, karena callback biasanya tidak membutuhkan this sendiri dan lebih baik mewarisi lingkup metode yang menuliskannya.
Demo handler pada browser#
Pada browser, aturan this untuk event handler, yaitu fungsi yang dipasang untuk merespons sebuah event, berjalan berbeda dari Node.js. Handler yang ditulis sebagai fungsi biasa menerima elemen yang dipasangi listener sebagai this, sedangkan handler arrow tetap mewarisi this lingkup luarnya. Demo berikut memasang dua handler pada satu object catatan, satu fungsi biasa dan satu arrow, lalu mencatat isi this.judul saat tombolnya diklik. Klik kedua tombol dan bandingkan baris pada log.
Kode sumber demo
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<title>Demo this pada handler</title>
<style>
body { font-family: "Segoe UI", Arial, sans-serif; margin: 14px; font-size: 14px; color: #1f2937; }
button { padding: 6px 12px; margin-right: 8px; margin-bottom: 10px; cursor: pointer; }
ol { font-size: 13px; line-height: 1.7; }
</style>
</head>
<body>
<p>Klik kedua tombol dan bandingkan isi this pada log.</p>
<button id="tombol-fungsi" type="button">Handler fungsi biasa</button>
<button id="tombol-arrow" type="button">Handler arrow</button>
<ol id="log"></ol>
<script src="index.js"></script>
<script>
// Demo this pada handler, fungsi biasa menerima elemen, arrow mewarisi lingkup luarnya.
const log = document.getElementById("log");
function catat(pesan) {
const baris = document.createElement("li");
baris.textContent = pesan;
log.appendChild(baris);
}
const catatan = {
judul: "Catatan harian",
pasang() {
document.getElementById("tombol-fungsi").addEventListener("click", function () {
catat("fungsi biasa, this adalah elemen tombol, this.judul = " + this.judul);
});
document.getElementById("tombol-arrow").addEventListener("click", () => {
catat("arrow, this adalah catatan, this.judul = " + this.judul);
});
}
};
catatan.pasang();
</script>
<script>
// Demo this pada handler, fungsi biasa menerima elemen, arrow mewarisi lingkup luarnya.
const log = document.getElementById("log");
function catat(pesan) {
const baris = document.createElement("li");
baris.textContent = pesan;
log.appendChild(baris);
}
const catatan = {
judul: "Catatan harian",
pasang() {
document.getElementById("tombol-fungsi").addEventListener("click", function () {
catat("fungsi biasa, this adalah elemen tombol, this.judul = " + this.judul);
});
document.getElementById("tombol-arrow").addEventListener("click", () => {
catat("arrow, this adalah catatan, this.judul = " + this.judul);
});
}
};
catatan.pasang();
</script></body>
</html>Tombol pertama melaporkan undefined karena this-nya adalah elemen tombol, dan elemen itu tidak punya properti judul. Tombol kedua melaporkan judul catatan karena arrow di dalam metode pasang mewarisi this milik metode tersebut, yaitu object catatan. Kedua perilaku itu sama-sama berguna. Handler fungsi biasa memberi akses langsung ke elemen yang diklik, sedangkan arrow menjaga this tetap menunjuk object yang menuliskannya.
Kapan arrow justru keliru#
Arrow menjadi pilihan keliru bila fungsinya membutuhkan this milik object tempat ia ditulis, misalnya sebagai metode object yang membaca datanya sendiri. Karena arrow tidak membuat this, this di dalam metode arrow tidak pernah menunjuk object di depan titik, apa pun bentuk pemanggilannya. Arrow juga tidak dapat dipanggil dengan new karena tidak memiliki mekanisme pembuatan object milik fungsi biasa.
// Arrow sebagai metode object yang butuh this adalah pilihan keliru.
const akun = {
pemilik: "Budi",
sapaDenganArrow: () => "Halo, " + this.pemilik,
sapaDenganFungsi() {
return "Halo, " + this.pemilik;
}
};
console.log(akun.sapaDenganArrow());
console.log(akun.sapaDenganFungsi());
const buatAkun = () => ({ pemilik: "Budi" });
try {
new buatAkun();
} catch (error) {
console.log(error.name + ": " + error.message);
}Halo, undefined
Halo, Budi
TypeError: buatAkun is not a constructorMetode arrow menghasilkan Halo, undefined karena this-nya diambil dari lingkup di luarnya, bukan dari akun, sedangkan metode fungsi biasa membaca this.pemilik dengan benar. Pemanggilan new buatAkun() juga menemui error TypeError karena arrow tidak bisa berperan sebagai konstruktor. Panduan praktisnya, tulis metode object dengan bentuk singkat fungsi biasa bila this-nya dibutuhkan, dan gunakan arrow untuk callback yang tidak membutuhkan this sendiri.
Ringkasan#
- Arrow function tidak memiliki this sendiri,
thisdi dalamnya dicari ke lingkup leksikal luarnya sehingga disebut this leksikal. - Callback fungsi biasa yang dipanggil lepas kehilangan this, sedangkan callback arrow mempertahankan this dari metode yang menuliskannya.
- Pada event handler browser, fungsi biasa menerima elemen yang dipasangi listener sebagai this, sedangkan arrow mewarisi lingkup luarnya.
- Arrow keliru dipakai sebagai metode object yang membutuhkan this dan tidak dapat dipanggil dengan
new.
Referensi#
- Arrow functions — MDN Web Docs — perilaku this pada arrow function menurut dokumentasi resmi.
- Arrow functions revisited — The Modern JavaScript Tutorial — perbandingan arrow dan fungsi biasa dari sisi this.
- this — MDN Web Docs — rujukan aturan penentuan this yang menjadi dasar perilaku ini.