Function Expression vs Declaration
Dua cara membuat fungsi dan perbedaan pentingnya: hoisting, kapan masing-masing dipakai, dan jebakan urutan definisi.
Analogi: Nama Jalan vs Alamat di Kertas
Bayangkan dua cara memberi tahu alamat. Cara pertama: plang nama jalan resmi yang dipasang pemerintah, semua orang bisa menemukannya kapan pun, bahkan sebelum melihat peta. Cara kedua: alamat yang ditulis tangan di secarik kertas, hanya berguna setelah kertasnya ada di tanganmu. Function declaration seperti plang nama jalan: JavaScript "memasangnya" duluan sebelum kode dijalankan (disebut hoisting), jadi bisa dipanggil bahkan sebelum baris definisinya. Function expression seperti alamat di kertas: fungsi disimpan sebagai NILAI di dalam variabel, dan baru ada setelah baris itu dieksekusi. Keduanya mengantarmu ke tujuan yang sama, tapi aturan mainnya berbeda, dan salah paham soal ini adalah sumber error klasik pemula.
Kenapa Dua Cara Ini Ada?
Awalnya JavaScript hanya punya declaration: pernyataan function nama() {...} yang berdiri sendiri. Lalu programmer menyadari fungsi sebenarnya bisa diperlakukan seperti nilai lain: disimpan di variabel, dimasukkan ke array, diberikan sebagai argumen. Untuk itu butuh cara membuat fungsi sebagai EKSPRESI (nilai), bukan pernyataan. Dari sinilah lahir const f = function() {...} dan kemudian arrow function. Perbedaan praktis terbesarnya adalah hoisting: declaration "diangkat" sehingga aman dipanggil lebih awal, expression mengikuti aturan variabel const sehingga mati sebelum dideklarasikan. Di kode modern, expression (terutama arrow) justru lebih populer karena fungsinya eksplisit sebagai nilai yang bisa dioper ke mana-mana, misalnya sebagai callback ke map atau setTimeout.
Contoh 1: Dua Cara, Hasil Sama
// Cara 1: Declaration (pernyataan fungsi)
function sapaDeklarasi(nama) {
return "Halo, " + nama;
}
// Cara 2: Expression (fungsi sebagai nilai di variabel)
const sapaEkspresi = function(nama) {
return "Halo, " + nama;
};
console.log(sapaDeklarasi("Budi")); // "Halo, Budi"
console.log(sapaEkspresi("Budi")); // "Halo, Budi"Dipanggil dengan cara yang identik, hasilnya identik. Perbedaannya baru terlihat saat kamu mencoba memanggil SEBELUM baris definisi:
sapaAwal(); // BERHASIL! declaration di-hoist ke atas
function sapaAwal() {
return "Halo dari declaration";
}
sapaTerlambat(); // ERROR: Cannot access before initialization
const sapaTerlambat = function() {
return "Halo dari expression";
};Expression tunduk pada aturan const: variabelnya ada di "zona mati" sampai baris deklarasinya dieksekusi. Memakainya lebih awal sama saja memakai variabel yang belum ada.
Contoh 2: Kasus Nyata, Callback dan Handler
Di aplikasi nyata, expression adalah cara utama membuat fungsi sekali pakai yang langsung diberikan ke fungsi lain:
// Daftar tugas: tiap tombol butuh aksi klik berbeda
const tombol = ["Simpan", "Hapus", "Batal"];
// Expression (arrow) sebagai callback: ringkas dan langsung di tempat
tombol.forEach(function(nama) {
console.log("Tombol " + nama + " siap dipasang handler");
});
// Contoh nyata kedua: fungsi di dalam object konfigurasi
const kalkulator = {
tambah: function(a, b) { return a + b; },
kali: (a, b) => a * b,
};
console.log(kalkulator.tambah(2, 3)); // 5
console.log(kalkulator.kali(2, 3)); // 6Pola "fungsi sebagai nilai" ini ada di mana-mana: event handler, callback API, method di object, middleware. Declaration cocok untuk fungsi utama yang berdiri sendiri dan ingin bisa dipanggil dari mana saja di file. Expression cocok saat fungsi adalah "barang" yang disimpan, dioper, atau dipakai sekali lalu dibuang.
Kesalahan Umum Pemula
1. Memanggil expression sebelum didefinisikan.
// SALAH: dikira sama seperti declaration
hitung(); // ERROR!
const hitung = function() {
return 42;
};
// BENAR: definisikan dulu, panggil kemudian
const hitung2 = function() {
return 42;
};
hitung2(); // 42Kalau kodenya disusun "panggil dulu, definisi belakangan" (gaya yang umum di tutorial lama), pakai declaration. Kalau pakai expression/arrow, disiplin: definisi selalu di atas pemakaian.
2. Lupa bahwa expression butuh nama variabel yang jelas.
// SALAH: anonymous tanpa nama variabel bermakna, susah dilacak saat error
const f = function(x) { return x * 2; };
// BENAR: nama variabel menjelaskan fungsi
const dobelkan = function(x) { return x * 2; };
// LEBIH BAIK untuk debugging: named function expression
const dobelkan2 = function dobelkan(x) { return x * 2; };Named function expression (const f = function nama() {}) membuat nama muncul di stack trace saat error, sangat membantu debugging. Untuk arrow function, nama variabelnya sendiri yang muncul.
3. Mencoba memakai expression sebagai constructor.
// SALAH: arrow function tidak bisa di-new
const BuatUser = (nama) => { this.nama = nama; };
// const u = new BuatUser("Budi"); // ERROR: not a constructor
// BENAR: constructor pakai function biasa (atau class)
function BuatUser(nama) {
this.nama = nama;
}
const u = new BuatUser("Budi");
console.log(u.nama); // "Budi"Ringkasan
Declaration (function nama() {...}) di-hoist sehingga bisa dipanggil sebelum baris definisinya, cocok untuk fungsi utama. Expression (const f = function() {...} atau arrow) memperlakukan fungsi sebagai nilai yang disimpan di variabel, tunduk pada aturan const sehingga harus didefinisikan dulu sebelum dipakai, dan bersinar sebagai callback. Pilih declaration untuk keterbacaan fungsi utama, expression untuk fungsi sebagai nilai. Yang terpenting: jangan pernah memanggil expression sebelum baris definisinya dieksekusi.
export default function App(): JSX.Element { return <h1>Hello world</h1> }
Tantangan
Tebak Hoisting
Tanpa menjalankan dulu, tebak output kode ini, lalu cek di playground. Jelaskan kenapa dalam komentar:
foo();
function foo() { console.log("A"); }
bar();
const bar = function() { console.log("B"); };
``` Memahami perbedaan hoisting declaration vs expression adalah bekal wajib sebelum masuk ke codebase nyata, karena error "cannot access before initialization" adalah salah satu error paling sering ditemui pemula saat membaca kode orang lain.<!doctype html> <html> <head> <meta charset="utf-8" /> </head> <body> <h1>Halo JS</h1> <p>Buka console preview untuk melihat output.</p> <script src="index.js"></script> </body> </html>