kodingup.camp

Beranda/JavaScript Mastery: Object & Data

Perilaku dan Interaksi Object

Modul 2 dari 143 menit bacaObject Behavior & Interaction

Isi modul

    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:

    call, apply, bind

    Ketiganya adalah method milik setiap function untuk mengatur this secara manual:

    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

    1. Memakai arrow function untuk method object. this di dalamnya bukan object tersebut. Pakai method shorthand nama() {}.
    2. Mengirim method sebagai callback tanpa bind. setTimeout(obj.method, 100) membuat this hilang. Pakai obj.method.bind(obj) atau bungkus () => obj.method().
    3. Memakai function biasa sebagai callback di dalam method. this.list.forEach(function (x) { this.total }) gagal karena function biasa punya this sendiri. Ganti dengan arrow function.
    4. Mengira bind langsung menjalankan function. bind hanya membuat function baru. Untuk langsung menjalankan, pakai call atau apply.
    5. Mencoba mengubah this arrow function dengan call. Tidak akan berpengaruh; arrow function selalu memakai this lexical.

    Latihan

    1. Mudah, Buat object mobil dengan properti merek dan method klakson() yang mengembalikan teks "<merek>: Tin tin!".
    2. Sedang, Diberikan function function info(kota) { return this.nama + " dari " + kota; } dan object { nama: "Sinta" }. Panggil info memakai call, apply, dan bind, ketiganya menghasilkan "Sinta dari Bogor".
    3. Menantang, Buat object timer dengan properti detik: 0 dan method mulai(n) yang memakai [...Array(n)].forEach(...) untuk menambah detik sebanyak n kali. Pastikan memakai arrow function supaya this benar, lalu kembalikan this.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

    Kuis pemahaman

    Pilih satu jawaban per soal. Penjelasan muncul setelah kamu menjawab.