Function adalah unit pengemasan logika yang paling dasar: satu blok kode bernama yang menerima masukan, mengolahnya, dan mengembalikan hasil. Di Node.js, function memegang peran jauh lebih besar daripada sekadar organisasi kode — function adalah warga kelas satu (first-class citizen) yang bisa disimpan ke variabel, dikirim sebagai argumen, dan dikembalikan dari function lain, sehingga seluruh pola asynchronous Node.js berdiri di atasnya. Pada chapter ini kita akan membandingkan tiga bentuk penulisan function, mengupas perilaku kata kunci this yang membedakan arrow function dari function biasa, lalu memakai default parameter dan rest parameter untuk membuat function yang lentur.

Tiga Bentuk Function #

JavaScript menyediakan tiga cara membuat function, dan ketiganya masih kita temui di kode Node.js masa kini. Function declaration adalah bentuk klasik dengan kata kunci function; function expression menempatkan function sebagai nilai yang disimpan ke variabel; arrow function adalah sintaks ringkas sejak ES 2015. Perbedaan teknis terpenting antara declaration dan dua bentuk lainnya ada pada hoisting — persis seperti yang kita lihat pada Chapter Variabel dan Scope. Simpan berikut sebagai bentuk-function.mjs:

js
// Function declaration diangkat (hoisted), jadi bisa dipanggil lebih dulu
console.log(`luas persegi 4x4 : ${luasPersegi(4)}`);

function luasPersegi(sisi) {
  return sisi * sisi;
}

// Function expression: nilainya baru tersedia setelah baris ini
const konversiSuhu = function (celsius) {
  return celsius * 1.8 + 32;
};

// Arrow function untuk operasi ringkas
const sapa = (nama) => `Halo, ${nama}! Selamat belajar.`;

console.log(`100 C dalam F    : ${konversiSuhu(100)}`);
console.log(sapa("Budi"));

Output yang Dihasilkan:

text
luas persegi 4x4 : 16
100 C dalam F    : 212
Halo, Budi! Selamat belajar.

Mari kita telaah baris-baris kode di atas:

  1. Baris 2-3: luasPersegi(4) dipanggil sebelum baris function luasPersegi dieksekusi. Pemanggilan ini berhasil karena function declaration diangkat beserta isinya ke awal scope.
  2. Baris 10 (const konversiSuhu = function ...): function expression mengikuti aturan const — baru bisa dipakai setelah baris deklarasinya berjalan, dan tidak bisa dipanggil lebih dulu.
  3. Baris 15 (const sapa = (nama) => ...): arrow function satu ekspresi tidak butuh kurung kurawal maupun return; nilai ekspresi langsung menjadi hasil function. Untuk badan lebih dari satu baris, kita tetap menulis { ... return ... }.

Arrow Function dan Kata Kunci this #

Perbedaan paling substansial arrow function bukan penulisan yang pendek, melainkan cara this diperlakukan. Function biasa mendefinisikan this sendiri setiap kali dipanggil: ketika dipanggil sebagai method tugas.ringkasReguler(), nilai this menunjuk object tugas. Arrow function tidak memiliki this sendiri — arrow function meminjam this dari scope tempat arrow function ditulis, apa pun cara pemanggilannya. Berkas arrow-this.mjs memperlihatkan akibatnya:

js
const tugas = {
  judul: "Belajar Node.js",
  durasiJam: 2,

  // Method biasa: this menunjuk object pemilik method
  ringkasReguler() {
    return `${this.judul} (${this.durasiJam} jam)`;
  },

  // Arrow function: tidak punya this sendiri,
  // this diambil dari scope luar (module scope, bernilai undefined)
  ringkasArrow: () => {
    return `${this.judul} (${this.durasiJam} jam)`;
  },
};

console.log(tugas.ringkasReguler());

try {
  console.log(tugas.ringkasArrow());
} catch (e) {
  console.log(`${e.name}: ${e.message}`);
}

Output yang Dihasilkan:

text
Belajar Node.js (2 jam)
TypeError: Cannot read properties of undefined (reading 'judul')

Penjelasan kedua hasilnya:

  1. ringkasReguler() mengembalikan ringkasan dengan benar. Ekspresi pemanggilan berbentuk object.method(), sehingga this di dalam method menunjuk object tugas dan this.judul terbaca.
  2. ringkasArrow() melempar TypeError karena this di dalam arrow function tidak menunjuk tugas, melainkan diambil dari scope luar — scope module. Pada berkas .mjs, this level module bernilai undefined, sehingga this.judul sama dengan membaca property dari undefined.

Parameter Bawaan dan Rest Parameter #

Function modern JavaScript punya dua fitur parameter yang menggantikan trik lama seperti argumen || nilaiBawaan. Default parameter mengisi nilai cadangan ketika argumen yang masuk bernilai undefined, sedangkan rest parameter menampung sisa argumen menjadi array sungguhan. Keduanya dirangkum dalam parameter.mjs:

js
// Default parameter: dipakai bila argumen bernilai undefined
function buatSambutan(nama, salam = "Selamat datang") {
  return `${salam}, ${nama}!`;
}

// Rest parameter: kumpulkan sisa argumen menjadi array
function hitungTotal(...angka) {
  let total = 0;
  for (let i = 0; i < angka.length; i++) {
    total += angka[i];
  }
  return total;
}

// Kombinasi: parameter biasa di depan, rest di belakang
function catatLog(level, ...pesan) {
  return `[${level}] ${pesan.join(" ")}`;
}

console.log(buatSambutan("Budi"));
console.log(buatSambutan("Siti", "Selamat pagi"));
console.log(`total : ${hitungTotal(1500, 2000, 500)}`);
console.log(catatLog("info", "server", "menyala", "di port 3000"));

Output yang Dihasilkan:

text
Selamat datang, Budi!
Selamat pagi, Siti!
total : 4000
[info] server menyala di port 3000

Mari kita bedah perilakunya:

  1. Baris 23 (buatSambutan("Budi")): argumen kedua tidak dikirim, jadi salam terisi default "Selamat datang". Pemanggilan kedua mengirim "Selamat pagi" sehingga default diabaikan.
  2. Baris 9 (...angka): tiga argumen 1500, 2000, 500 terkumpul menjadi array [1500, 2000, 500] di dalam function, lalu dijumlahkan dengan loop biasa.
  3. Baris 17 (catatLog): parameter level menangkap argumen pertama, sisanya masuk pesan. Method join(" ") merangkai array menjadi satu kalimat. Perhatikan bahwa rest parameter harus selalu berada di posisi terakhir.

Function sebagai Nilai #

Karena function adalah nilai, function bisa dikirim sebagai argumen ke function lain — function yang menerima function seperti ini disebut higher-order function, dan function yang dikirim disebut callback. Pola inilah yang dipakai hampir seluruh API Node.js, dari pembacaan berkas hingga penanganan request HTTP. Versi paling sederhananya terlihat seperti ini:

js
function jalankanTugas(nama, selesai) {
  console.log(`menjalankan ${nama}...`);
  selesai(`tugas ${nama} selesai`);
}

jalankanTugas("backup", function (hasil) {
  console.log(`callback: ${hasil}`);
});

Output yang Dihasilkan:

text
menjalankan backup...
callback: tugas backup selesai

Function jalankanTugas menerima dua argumen: string nama dan function selesai. Di dalam badannya, jalankanTugas memutuskan kapan callback dipanggil — di sini tepat setelah pesan “menjalankan” dicetak. Pemanggilan selesai(...) menjalankan function anonim yang kita kirim, dan hasilnya dicetak dari dalam callback. Pada kode nyata Node.js, callback seperti ini dijalankan setelah operasi lambat selesai, bukan seketika; mekanisme penjadwalannya akan kita bahas tuntas pada Section Asynchronous Runtime.

Referensi lanjutan untuk topik chapter ini:

Kita kini bisa menulis function dalam tiga bentuk dan memilih bentuk yang tepat untuk konteksnya. Seiring aplikasi tumbuh, function menerima semakin banyak data terstruktur sebagai masukan — object. Chapter berikutnya, Object dan Destructuring, memperkenalkan cara membaca dan membentuk object yang ringkas serta aman.