Kenapa ini penting
Object bukan hanya wadah data. Object juga bisa punya perilaku: function yang menempel di object disebut method. Akun bank punya saldo (data) dan bisa setor() atau tarik() (perilaku). Keranjang belanja punya daftar item dan bisa hitungTotal().
Di dalam method, kamu sering butuh merujuk ke "object pemilik method ini". Untuk itu JavaScript menyediakan kata kunci this. Masalahnya, this di JavaScript tidak tetap: nilainya ditentukan oleh cara function dipanggil, bukan oleh tempat function ditulis. Inilah sumber bug yang sangat sering muncul, misalnya method yang tiba-tiba kehilangan datanya saat dipakai sebagai callback tombol atau setTimeout. Kalau kamu paham aturan this, kamu akan jauh lebih percaya diri membaca kode library dan framework.
Konsep inti
Method
Method adalah function yang disimpan sebagai properti object. Penulisan modern memakai method shorthand: setor(jumlah) { ... }.
Aturan this untuk function biasa (regular function)
Analogi: this itu seperti kata "saya" dalam kalimat. Kalimat "Saya lapar" artinya tergantung siapa yang mengucapkannya. Kalimatnya sama, pembicaranya beda, maknanya beda.
| Cara memanggil | Nilai this |
|---|---|
obj.method() |
obj (object di kiri titik) |
fn() biasa (tanpa titik) |
undefined di strict mode/module, object global di mode non-strict |
fn.call(x) / fn.apply(x) |
x |
fn.bind(x) lalu dipanggil |
selalu x |
new Fn() |
object baru yang sedang dibuat |
Strict mode aktif otomatis di dalam ES module dan class. Di file script biasa kamu bisa mengaktifkannya dengan menulis "use strict"; di baris paling atas. Modul-modul berikutnya mengasumsikan strict mode karena itulah perilaku kode modern.
Kehilangan this
Saat kamu mengambil method dari object lalu menyimpannya ke variabel, hubungan dengan object pemiliknya putus. const f = akun.setor; f(100) memanggil f tanpa titik, jadi this bukan akun lagi. Hal yang sama terjadi saat method dikirim sebagai callback: setTimeout(akun.cetak, 1000).
Arrow function vs regular function
Arrow function (() => {}) tidak punya this sendiri. Ia "meminjam" this dari lingkup tempat ia ditulis (disebut lexical this). Akibatnya:
- Arrow function bagus dipakai sebagai callback di dalam method, karena tetap memakai
thismilik method luarnya. - Arrow function buruk dipakai sebagai method object, karena
this-nya bukan object tersebut. call,apply, danbindtidak bisa mengubahthismilik arrow function.
call, apply, bind
Ketiganya adalah method milik setiap function untuk mengatur this secara manual:
fn.call(thisArg, a, b)memanggil langsung, argumen dipisah koma.fn.apply(thisArg, [a, b])memanggil langsung, argumen dalam array. Cara mengingat: Apply = Array.fn.bind(thisArg, a)tidak memanggil, tapi mengembalikan function baru yangthis-nya terkunci. Argumen yang diberikan kebindikut terkunci di depan (disebut partial application).
Contoh kode
"use strict";
// 1) Method dan this
const akun = {
pemilik: "Dewi",
saldo: 100000,
setor(jumlah) {
this.saldo += jumlah; // this = akun karena dipanggil akun.setor()
return this.saldo;
},
};
console.log(akun.setor(50000)); // → 150000
// 2) Kehilangan this
const setorLepas = akun.setor;
try {
setorLepas(1000); // dipanggil tanpa titik → this = undefined
} catch (err) {
console.log(err instanceof TypeError); // → true
}
// 3) Arrow function sebagai method: jebakan
const lampu = {
status: "mati",
nyalakanSalah: () => {
return this === lampu; // this diambil dari lingkup luar, BUKAN object lampu
},
nyalakan() {
this.status = "nyala";
return this.status;
},
};
console.log(lampu.nyalakanSalah()); // → false
console.log(lampu.nyalakan()); // → nyala
// 4) Arrow function sebagai callback di dalam method: tepat
const kelas = {
guru: "Bu Ani",
murid: ["Andi", "Budi"],
absen() {
// arrow function meminjam this dari absen(), yaitu kelas
return this.murid.map((m) => `${m} diabsen oleh ${this.guru}`);
},
};
console.log(kelas.absen());
// → [ 'Andi diabsen oleh Bu Ani', 'Budi diabsen oleh Bu Ani' ]
// 5) call dan apply
function perkenalan(salam, tanda) {
return `${salam}, saya ${this.nama}${tanda}`;
}
const orang1 = { nama: "Rudi" };
console.log(perkenalan.call(orang1, "Halo", "!")); // → Halo, saya Rudi!
console.log(perkenalan.apply(orang1, ["Hai", "."])); // → Hai, saya Rudi.
// 6) bind: mengunci this untuk dipakai nanti
const cetakSaldo = function () {
return `Saldo ${this.pemilik}: ${this.saldo}`;
}.bind(akun);
console.log(cetakSaldo()); // → Saldo Dewi: 150000
// bind juga bisa mengunci argumen di depan (partial application)
function kali(a, b) {
return a * b;
}
const kaliDua = kali.bind(null, 2);
console.log(kaliDua(21)); // → 42
// 7) Memperbaiki callback yang kehilangan this
const penghitung = {
nilai: 0,
tambah() {
this.nilai++;
return this.nilai;
},
};
const jalankan = (callback) => callback();
console.log(jalankan(penghitung.tambah.bind(penghitung))); // → 1
console.log(jalankan(() => penghitung.tambah())); // → 2
Kesalahan umum
- Memakai arrow function untuk method object.
thisdi dalamnya bukan object tersebut. Pakai method shorthandnama() {}. - Mengirim method sebagai callback tanpa
bind.setTimeout(obj.method, 100)membuatthishilang. Pakaiobj.method.bind(obj)atau bungkus() => obj.method(). - Memakai
functionbiasa sebagai callback di dalam method.this.list.forEach(function (x) { this.total })gagal karena function biasa punyathissendiri. Ganti dengan arrow function. - Mengira
bindlangsung menjalankan function.bindhanya membuat function baru. Untuk langsung menjalankan, pakaicallatauapply. - Mencoba mengubah
thisarrow function dengancall. Tidak akan berpengaruh; arrow function selalu memakaithislexical.
Latihan
- Mudah, Buat object
mobildengan propertimerekdan methodklakson()yang mengembalikan teks"<merek>: Tin tin!". - Sedang, Diberikan function
function info(kota) { return this.nama + " dari " + kota; }dan object{ nama: "Sinta" }. Panggilinfomemakaicall,apply, danbind, ketiganya menghasilkan"Sinta dari Bogor". - Menantang, Buat object
timerdengan propertidetik: 0dan methodmulai(n)yang memakai[...Array(n)].forEach(...)untuk menambahdetiksebanyaknkali. Pastikan memakai arrow function supayathisbenar, lalu kembalikanthis.detik.
Lihat solusi
// 1) Mudah
const mobil = {
merek: "Avanza",
klakson() {
return `${this.merek}: Tin tin!`;
},
};
console.log(mobil.klakson()); // → Avanza: Tin tin!
// 2) Sedang
function info(kota) {
return this.nama + " dari " + kota;
}
const orang = { nama: "Sinta" };
console.log(info.call(orang, "Bogor")); // → Sinta dari Bogor
console.log(info.apply(orang, ["Bogor"])); // → Sinta dari Bogor
console.log(info.bind(orang)("Bogor")); // → Sinta dari Bogor
// 3) Menantang
const timer = {
detik: 0,
mulai(n) {
[...Array(n)].forEach(() => {
this.detik++; // arrow function: this tetap timer
});
return this.detik;
},
};
console.log(timer.mulai(5)); // → 5
Ringkasan
- Method adalah function di dalam object; di dalamnya
thismerujuk ke object yang memanggilnya. - Nilai
thispada function biasa ditentukan oleh cara pemanggilan, bukan tempat penulisan. - Arrow function tidak punya
thissendiri, cocok untuk callback di dalam method, tidak cocok sebagai method. calldanapplymemanggil function denganthistertentu;applymenerima argumen berupa array.bindmengembalikan function baru denganthis(dan argumen awal) yang terkunci.