Deklarasi fungsi

Parameter, nilai balik, dan hoisting pada deklarasi fungsi.

Daftar isi

Fungsi adalah blok kode yang diberi nama dan dapat dipanggil berulang kali dengan masukan yang berbeda-beda. Topik ini menyusun dasar penulisan fungsi di JavaScript, yaitu deklarasi, perbedaan parameter dan argumen, serta nilai balik yang dihasilkan. Setelah membacanya, fungsi dapat dideklarasikan dan dipanggil dengan benar, perilaku return dipahami tanpa perlu menebak, dan perbedaan deklarasi fungsi dengan ekspresi fungsi diketahui beserta akibatnya pada urutan eksekusi. Seluruh contoh berupa berkas JavaScript utuh yang dapat dijalankan dengan Node.js.

Deklarasi dan pemanggilan#

Deklarasi fungsi diawali kata kunci function, disusul nama fungsinya, daftar parameter dalam tanda kurung, dan tubuh fungsi dalam tanda kurung kurawal. Nama fungsinya sebaiknya berupa kata kerja yang menjelaskan pekerjaannya, misalnya celsiusKeFahrenheit atau hitungDiskon, sehingga baris pemanggilannya terbaca seperti instruksi, “hitung konversi suhu dari 25”. Tubuh fungsi berisi langkah-langkahnya dan biasanya diakhiri return untuk menghasilkan nilai. Fungsi baru benar-benar berjalan ketika dipanggil dengan menuliskan namanya diikuti tanda kurung, dan setiap pemanggilan mengulang seluruh langkah di dalamnya dengan masukan yang diberikan.

Berkas berikut mendeklarasikan fungsi konversi suhu, lalu memanggilnya tiga kali dengan masukan yang berbeda.

js konversi-suhu.js
// Konversi suhu dari Celsius ke Fahrenheit dengan deklarasi fungsi.

function celsiusKeFahrenheit(celsius) {
  const fahrenheit = (celsius * 9) / 5 + 32;
  return fahrenheit;
}

console.log(celsiusKeFahrenheit(0));
console.log(celsiusKeFahrenheit(25));
console.log(celsiusKeFahrenheit(100));
text Keluaran
32
77
212

Keluarannya mengikuti urutan pemanggilan, dan setiap pemanggilan bekerja dengan masukannya sendiri tanpa mengganggu pemanggilan lain. Untuk mencobanya di terminal, buat berkasnya dari blok kode di atas lalu jalankan dengan Node.js.

bash
# pastikan berada di direktori tempat konversi-suhu.js disimpan
node konversi-suhu.js
text Keluaran
32
77
212

Parameter dan argumen#

Parameter adalah nama di dalam tanda kurung pada definisi fungsi, sedangkan argumen adalah nilai nyata yang dioper saat fungsi dipanggil. Pada fungsi kali(a, b), a dan b adalah parameter, sedangkan 6 dan 7 pada pemanggilan kali(6, 7) adalah argumen. Posisi argumen menentukan parameter yang menerimanya, sehingga urutannya harus dipertahankan. Jumlahnya pun boleh tidak pas, dan JavaScript tidak memunculkan error untuk ketidaksesuaian itu. Bila argumennya kurang, parameter yang tersisa terisi undefined, sedangkan argumen lebih dibiarkan tanpa pemakai.

Berkas berikut memperagakan dua pemanggilan, satu dengan argumen lengkap dan satu dengan argumen kurang.

js kali-argumen.js
// Parameter adalah nama di definisi, argumen adalah nilai saat pemanggilan.

function kali(a, b) {
  return a * b;
}

console.log(kali(6, 7));
console.log(kali(6));
text Keluaran
42
NaN

Pemanggilan kali(6) menghasilkan NaN (not a number), nilai khusus yang muncul bila perhitungan matematika tidak punya hasil yang masuk akal. Sebabnya, 6 * undefined tidak dapat dihitung. Kasus seperti ini sering bukan error yang terlempar, melainkan angka yang salah diam-diam merambat ke perhitungan berikutnya. Nilai default pada parameter menutup celah ini dan dibahas pada topik Parameter default dan rest.

Nilai balik dengan return#

Pernyataan return menghentikan eksekusi fungsi dan mengembalikan satu nilai ke pemanggilnya. Nilai itu dapat disimpan ke variabel, dioper ke fungsi lain, atau langsung dipakai dalam ekspresi. Eksekusi berhenti tepat pada baris return, sehingga pernyataan sesudahnya tidak pernah dijalankan, dan sifat ini sering dimanfaatkan untuk keluar dini dari fungsi saat kondisi tertentu sudah tercapai. Fungsi yang tidak memuat return, atau memuatnya tanpa nilai, tetap mengembalikan sesuatu, yaitu undefined.

Berkas berikut membandingkan fungsi yang mengembalikan nilai dengan fungsi yang hanya mencetak.

js nilai-balik.js
// Fungsi dengan return menyimpan nilai, fungsi tanpa return mengembalikan undefined.

function diskon(nominal, persen) {
  return nominal * (persen / 100);
}

function cetakStruk(nominal, persen) {
  const potongan = diskon(nominal, persen);
  const bayar = nominal - potongan;
  console.log("nominal :", nominal);
  console.log("potongan:", potongan);
  console.log("bayar   :", bayar);
}

const potongan = diskon(120000, 25);
console.log("potongan yang tersimpan:", potongan);

const hasilCetak = cetakStruk(120000, 25);
console.log("nilai balik cetakStruk :", hasilCetak);
text Keluaran
potongan yang tersimpan: 30000
nominal : 120000
potongan: 30000
bayar   : 90000
nilai balik cetakStruk : undefined

Urutan keluarannya menegaskan perbedaan kedua fungsi. Fungsi diskon mengembalikan 30000 sehingga nilainya dapat disimpan dan dipakai lagi, sedangkan cetakStruk mencetak struk ke layar tetapi tidak mengembalikan apa pun, sehingga hasilCetak berisi undefined. Keduanya sah, tetapi pekerjaannya berbeda. Fungsi yang memproses data sebaiknya mengembalikan nilai dan menyerahkan pencetakan kepada pemanggilnya, karena nilai kembalian lebih mudah dipakai ulang daripada teks yang hanya muncul di layar.

Pola keluar dini memanfaatkan sifat return yang menghentikan fungsi langsung pada barisnya.

js Contoh: return sebagai keluar dini dari fungsi
function tandaAir(temperatur) {
  if (temperatur >= 100) {
    return "uap";
  }
  if (temperatur <= 0) {
    return "es";
  }
  return "cair";
}

console.log(tandaAir(100));
console.log(tandaAir(-4));
console.log(tandaAir(21));
text Keluaran
uap
es
cair

Pemeriksaan pertama yang cocok langsung mengembalikan hasil dan memotong sisa tubuh fungsi. Pola ini menghindari percabangan bersarang yang dalam karena setiap kondisi tidak perlu menunggu pernyataan else.

Satu nilai balik untuk banyak data#

return hanya membawa satu nilai, sehingga fungsi yang perlu menghasilkan banyak data membungkusnya dalam satu array atau satu object. Array dipilih bila urutan penting dan data-datanya sejenis, sedangkan object dipilih bila setiap data punya nama yang menjelaskan maknanya. Aturan ini bukan keterbatasan yang mengganggu, melainkan kontrak yang sederhana. Satu pemanggilan selalu menghasilkan tepat satu nilai, sehingga pemanggil tahu apa yang diterimanya.

Berkas berikut merangkum lima nilai ujian menjadi satu rekap berbentuk object dengan tiga properti.

js statistik-nilai.js
// Banyak data dikembalikan lewat satu object sebagai satu nilai balik.

function statistik(nilai) {
  let terendah = nilai[0];
  let tertinggi = nilai[0];
  let jumlah = 0;
  for (const n of nilai) {
    if (n < terendah) {
      terendah = n;
    }
    if (n > tertinggi) {
      tertinggi = n;
    }
    jumlah += n;
  }
  return { terendah, tertinggi, rataRata: jumlah / nilai.length };
}

const hasilUjian = [80, 72, 95, 68, 90];
const rekap = statistik(hasilUjian);
console.log(rekap);
console.log("rata-rata:", rekap.rataRata);
text Keluaran
{ terendah: 68, tertinggi: 95, rataRata: 81 }
rata-rata: 81

Fungsi statistik menghitung tiga angka sekaligus tetapi hanya memuat satu pernyataan return. Tiga hasil itu dibungkus object dengan properti terendah, tertinggi, dan rataRata, sehingga pemanggil membacanya lewat namanya, misalnya rekap.rataRata. Bila nama tidak diperlukan dan urutannya sudah disepakati, array sudah cukup, misalnya return [terendah, tertinggi].

Hoisting dan ekspresi fungsi#

Deklarasi fungsi punya perilaku khas bernama hoisting, yaitu deklarasi didaftarkan ke lingkupnya sebelum kode dijalankan, sehingga fungsi dapat dipanggil sebelum baris deklarasinya. Perilakunya murni mekanis. Ketika JavaScript menyiapkan sebuah lingkup, seluruh deklarasi fungsi di dalamnya dipasang lebih dahulu, baru kemudian kode dieksekusi baris demi baris. Ekspresi fungsi (function expression) bekerja sebaliknya, fungsi dibuat sebagai nilai lalu disimpan ke variabel. Aturannya mengikuti variabel itu, sehingga fungsi baru siap dipanggil setelah barisnya dijalankan.

Berkas berikut memanggil fungsi sebelum deklarasinya, lalu mencoba hal yang sama pada ekspresi fungsi.

js hoisting-demo.js
// Deklarasi fungsi dapat dipanggil sebelum barisnya, ekspresi fungsi tidak.

console.log(gandakan(5));

function gandakan(angka) {
  return angka * 2;
}

try {
  console.log(gandakanEkspresi(5));
} catch (error) {
  console.log("error:", error.message);
}

const gandakanEkspresi = function (angka) {
  return angka * 2;
};

console.log(gandakanEkspresi(5));
text Keluaran
10
error: Cannot access 'gandakanEkspresi' before initialization
10

Pemanggilan gandakan(5) sebelum deklarasinya berhasil karena hoisting, sedangkan pemanggilan gandakanEkspresi(5) sebelum barisnya memunculkan error karena variabel const baru dapat dipakai setelah baris deklarasinya dijalankan. Setelah baris itu terlewati, fungsi yang sama dapat dipanggil seperti biasa, dan baris terakhir pada keluaran membuktikannya.

Perbandingan ketiga bentuk penulisan fungsi dirangkum pada tabel berikut.

BentukContohDipanggil sebelum barisnya
Deklarasi fungsifunction gandakan(angka) { ... }Bisa, deklarasi terdaftar sejak awal lingkup
Ekspresi fungsiconst gandakan = function (angka) { ... }Tidak bisa, variabelnya belum terisi
Arrow functionconst gandakan = angka => angka * 2Tidak bisa, perilakunya sama dengan ekspresi fungsi

Ringkasan#

  • Deklarasi fungsi function nama(parameter) { ... } memberi nama pada blok kode, dan tubuhnya dijalankan setiap kali fungsi dipanggil dengan argumen.
  • Parameter adalah nama pada definisi dan argumen adalah nilai saat pemanggilan, argumen yang tidak terisi bernilai undefined sehingga perhitungannya dapat menghasilkan NaN.
  • return menghentikan fungsi dan mengembalikan tepat satu nilai, sehingga banyak data dibungkus array atau object, sedangkan fungsi tanpa return mengembalikan undefined.
  • Deklarasi fungsi dapat dipanggil sebelum barisnya karena hoisting, sedangkan ekspresi fungsi baru siap dipanggil setelah baris deklarasinya dijalankan.

Referensi#