JavaScript

Belum masuk. Progresmu tidak tersimpan.

Masuk
  • Bab 4 dari 12
  • 30 menit
  • 1 latihan kode
  • 4 soal kuis

Fungsi, Scope, dan Hoisting

Di bab ini (10 bagian)
  1. Tujuan
  2. Kenapa butuh fungsi?
  3. Function declaration vs function expression
  4. Parameter, argumen, dan return
  5. Callback sederhana
  6. Scope: siapa boleh melihat variabel?
  7. Closure dasar
  8. Hoisting dasar
  9. Kesalahan umum
  10. Rangkuman

Tujuan bab ini

  • Membedakan function declaration dan function expression, termasuk kapan masing-masing bisa dipanggil.
  • Memakai parameter, argumen, dan return dengan benar.
  • Memahami callback sederhana dan closure dasar.
  • Mengenali scope global, fungsi, dan blok, serta efek hoisting pada var dan function declaration.

Kenapa butuh fungsi?

Bayangkan kamu harus menghitung total belanja dengan diskon di sepuluh tempat berbeda dalam satu program. Kalau rumusnya ditulis ulang sepuluh kali, satu salah ketik saja bikin hasilnya beda-beda. Fungsi menyelesaikan masalah ini: kamu menulis logikanya sekali, memberinya nama, lalu memanggilnya kapan pun dibutuhkan. Kalau rumusnya berubah, kamu cukup mengubah satu tempat.

Anggap fungsi seperti resep. Resep punya bahan (parameter), langkah (isi fungsi), dan hasil jadi (nilai return). Resep yang sama bisa dipakai berkali-kali dengan bahan berbeda.

Function declaration vs function expression

Ada dua cara utama membuat fungsi di JavaScript.

// Function declaration
function tambah(a, b) {
  return a + b;
}

// Function expression: fungsi disimpan ke variabel
const kurang = function (a, b) {
  return a - b;
};

console.log(tambah(2, 3)); // 5
console.log(kurang(5, 2)); // 3

Sejak ES2015 (ES6) ada juga arrow function, bentuk ringkas dari function expression:

const kali = (a, b) => a * b;      // return otomatis kalau tanpa kurung kurawal
const sapa = nama => `Halo, ${nama}!`;

console.log(kali(4, 5));   // 20
console.log(sapa("Rani")); // Halo, Rani!

Perbedaan paling terasa antara declaration dan expression ada di kapan fungsi itu bisa dipanggil. Function declaration bisa dipanggil bahkan sebelum barisnya ditulis, sedangkan function expression baru bisa dipakai setelah baris penugasannya dijalankan. Kenapa begitu? Jawabannya ada di bagian hoisting nanti.

DeclarationExpression / arrow
Bentukfunction nama() {}const nama = function () {}
Dipanggil sebelum didefinisikanBisaTidak (error)
Cocok untukFungsi utama, helper umumCallback, fungsi yang dikirim ke fungsi lain

Parameter, argumen, dan return

Parameter adalah nama variabel di definisi fungsi. Argumen adalah nilai nyata yang kamu kirim saat memanggilnya. Di tambah(2, 3), parameternya a dan b, argumennya 2 dan 3.

JavaScript cukup santai soal jumlah argumen. Argumen yang tidak dikirim bernilai undefined, dan kamu bisa memberi nilai default (ES2015):

function salam(nama = "teman") {
  return "Halo, " + nama;
}

console.log(salam("Dika")); // Halo, Dika
console.log(salam());       // Halo, teman

return melakukan dua hal: mengirim nilai keluar dari fungsi dan menghentikan fungsi saat itu juga. Baris setelah return tidak akan dijalankan. Fungsi tanpa return tetap menghasilkan nilai, yaitu undefined.

function cekUmur(umur) {
  if (umur < 0) return "Umur tidak valid";
  return umur >= 17 ? "Dewasa" : "Remaja";
}

function cetak(pesan) {
  console.log(pesan); // hanya mencetak, tidak me-return
}

console.log(cekUmur(20));    // Dewasa
console.log(cetak("tes"));   // tes, lalu undefined

Ingat bedanya: console.log menampilkan sesuatu ke layar, sedangkan return mengembalikan nilai supaya bisa dipakai kode lain.

Callback sederhana

Di JavaScript, fungsi adalah nilai biasa. Ia bisa disimpan di variabel dan dikirim sebagai argumen ke fungsi lain. Fungsi yang dikirim itu disebut callback, karena akan "dipanggil balik" oleh fungsi penerimanya.

function prosesNilai(nilai, aksi) {
  return aksi(nilai);
}

const gandakan = x => x * 2;

console.log(prosesNilai(5, gandakan));      // 10
console.log(prosesNilai(5, x => x + 100));  // 105

Perhatikan: kita menulis gandakan, bukan gandakan(). Tanpa kurung berarti "kirim fungsinya", dengan kurung berarti "panggil sekarang dan kirim hasilnya". Pola callback ini akan sering kamu temui di method array seperti map dan filter, juga di addEventListener untuk DOM.

Scope: siapa boleh melihat variabel?

Scope adalah area tempat sebuah variabel bisa diakses. Ada tiga jenis yang perlu kamu kenal dulu:

  • Global scope: variabel di luar semua fungsi dan blok, bisa diakses di mana saja.
  • Function scope: variabel di dalam fungsi hanya hidup di fungsi itu.
  • Block scope: let dan const di dalam { } (misalnya if atau for) hanya hidup di blok itu.

Contoh global scope dan function scope

let pesan = "global";

function tampil() {
  let lokal = "di dalam fungsi";
  console.log(pesan); // global (boleh, scope luar terlihat dari dalam)
}

tampil();

if (true) {
  let blokLet = "let";
  var blokVar = "var";
}

console.log(blokVar);  // var  (var tidak peduli blok)
console.log(blokLet);  // ReferenceError: blokLet is not defined

Aturannya satu arah: kode di dalam bisa melihat variabel di luar, tapi kode di luar tidak bisa mengintip ke dalam. Seperti kaca film mobil, dari dalam kamu bisa melihat jalan, dari luar orang tidak bisa melihat ke dalam. var hanya menghormati batas fungsi, bukan batas blok, itulah salah satu alasan kita lebih memilih let dan const.

Closure dasar

Closure terjadi ketika sebuah fungsi mengingat variabel dari scope tempat ia dibuat, bahkan setelah fungsi luarnya selesai berjalan.

function buatPenghitung() {
  let hitung = 0;
  return function () {
    hitung++;
    return hitung;
  };
}

const klik = buatPenghitung();
console.log(klik()); // 1
console.log(klik()); // 2

const klikLain = buatPenghitung();
console.log(klikLain()); // 1 (punya hitung sendiri)

Langkah demi langkah: buatPenghitung() membuat variabel hitung, lalu mengembalikan fungsi dalam. Normalnya hitung hilang setelah fungsi selesai, tapi karena fungsi dalam masih memakainya, JavaScript menyimpannya. Setiap pemanggilan buatPenghitung() membuat hitung baru, jadi klik dan klikLain tidak saling ganggu. Closure berguna untuk menyimpan data "privat" yang tidak bisa diubah langsung dari luar.

Hoisting dasar

Sebelum menjalankan kode, JavaScript membaca dulu semua deklarasi di sebuah scope. Efeknya seolah deklarasi "diangkat" ke atas, makanya disebut hoisting.

console.log(sapaPagi()); // Selamat pagi (function declaration terangkat utuh)

function sapaPagi() {
  return "Selamat pagi";
}

console.log(skor); // undefined (var terangkat, nilainya belum)
var skor = 90;

console.log(level); // ReferenceError: Cannot access 'level' before initialization
let level = 3;
  • Function declaration terangkat lengkap dengan isinya, jadi bisa dipanggil lebih awal.
  • var terangkat namanya saja dan diisi undefined sampai baris penugasan.
  • let dan const juga dikenali lebih awal, tapi berada di temporal dead zone sampai barisnya dijalankan, sehingga mengaksesnya lebih dulu memicu ReferenceError.

Karena function expression disimpan di const atau let, ia ikut aturan yang ketiga. Itu sebabnya kurang() tidak bisa dipanggil sebelum didefinisikan.

Kesalahan umum

  • Lupa return. Fungsi menghitung dengan benar tapi hasilnya undefined karena hanya console.log, bukan return.
  • Memanggil callback terlalu cepat. Menulis prosesNilai(5, gandakan()) mengirim hasil panggilan, bukan fungsinya.
  • Arrow function dengan kurung kurawal tanpa return. x => { x * 2 } menghasilkan undefined; tulis x => x * 2 atau tambahkan return.
  • Mengandalkan var di dalam blok. Variabel "bocor" ke luar if atau for dan bisa menimpa variabel lain.
  • Mengandalkan hoisting. Kode yang memakai variabel sebelum dideklarasikan sulit dibaca; biasakan deklarasi di atas.

Rangkuman

  • Function declaration terangkat utuh, function expression dan arrow function baru bisa dipakai setelah didefinisikan.
  • Parameter ada di definisi, argumen dikirim saat memanggil; return mengirim nilai dan menghentikan fungsi.
  • Callback adalah fungsi yang dikirim sebagai argumen untuk dipanggil oleh fungsi lain.
  • let/const berscope blok, var berscope fungsi; dari dalam bisa melihat ke luar, tidak sebaliknya.
  • Closure membuat fungsi mengingat variabel dari tempat ia dibuat.

Selesaikan bab ini

  1. 1. Baca materi
  2. 2. Latihan kode (1)
  3. 3. Kuis (4 soal)

Latihan kode: Diskon, tabungan, dan callback

Lengkapi tiga fungsi berikut.

  1. hitungTotal(harga, diskon) mengembalikan harga setelah diskon dalam persen. Kalau diskon tidak dikirim, anggap 0. Contoh: hitungTotal(100000, 10) menghasilkan 90000.
  2. buatTabungan(awal) mengembalikan fungsi setor(jumlah). Setiap kali setor dipanggil, saldo bertambah dan saldo terbaru di-return. Setiap tabungan punya saldo sendiri (closure).
  3. prosesDua(a, b, aksi) memanggil callback aksi dengan a dan b, lalu mengembalikan hasilnya. Contoh: prosesDua(6, 7, (x, y) => x * y) menghasilkan 42.

Cek pemahaman

  1. 1Bentuk fungsi mana yang bisa dipanggil sebelum barisnya ditulis?

  2. 2Apa yang ditampilkan kode berikut?

    function buatPenghitung() {
      let n = 0;
      return () => ++n;
    }
    const a = buatPenghitung();
    const b = buatPenghitung();
    a();
    a();
    console.log(a() + b());
  3. 3Fungsi tanpa pernyataan return menghasilkan nilai null.

  4. 4Apa yang ditampilkan kode berikut?

    console.log(x);
    var x = 7;