7 Kesalahan Umum Saat Menulis Fungsi JavaScript
Fungsi JavaScript terlihat sederhana, tetapi jebakan halus sering muncul saat kode mulai kompleks. Kenali tujuh kesalahan yang paling sering terjadi dan cara menghindarinya.
Menulis fungsi di JavaScript terasa mudah sampai tiba-tiba kamu menemukan bug yang sulit dilacak. Masalahnya sering bukan pada logika besar, melainkan pada detail kecil seperti cakupan variabel, cara mengembalikan nilai, atau cara memanggil fungsi. Tujuh kesalahan berikut paling sering muncul. Setiap contoh menyertakan perbaikannya.
1. Lupa mengembalikan nilai dari fungsi
Fungsi yang tidak mengembalikan apa pun secara implisit menghasilkan undefined. Ini sering terjadi saat kamu menulis logika perhitungan tetapi lupa menambahkan return.
function hitungLuas(p, l) {
const luas = p * l;
// seharusnya return luas;
}
console.log(hitungLuas(3, 4)); // undefined
Tambahkan return sebelum nilai yang ingin dikirim keluar. Jika fungsi hanya melakukan efek samping seperti menulis ke DOM, tidak perlu mengembalikan nilai, tetapi pastikan pemanggilnya tidak mengharapkan hasil.
2. Menggunakan var di dalam loop yang membuat closure
Variabel yang dideklarasikan dengan var memiliki cakupan fungsi, bukan blok. Saat kamu membuat fungsi di dalam loop dengan var, semua closure akan merujuk ke nilai akhir variabel yang sama.
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
// Output: 3, 3, 3
Ganti var dengan let agar setiap iterasi memiliki binding sendiri. Untuk pembahasan lebih dalam tentang perilaku loop dan closure, lihat 7 Teknik Loop JavaScript yang Sering Dipakai Pro.
3. Tidak memahami perbedaan function dan arrow function dalam konteks this
Arrow function tidak memiliki this sendiri; ia mengambil this dari lingkungan sekitarnya. Ini bisa menjadi keuntungan, tetapi juga sumber kebingungan saat kamu menulis method objek atau event handler.
const obj = {
nama: 'Budi',
sapa: function() {
setTimeout(function() {
console.log(this.nama); // undefined
}, 100);
}
};
Di dalam setTimeout biasa, this merujuk ke objek global atau undefined (dalam mode strict). Gunakan arrow function atau simpan referensi this ke variabel lain sebelum memasukinya.
4. Melewatkan parameter yang diperlukan
JavaScript tidak memaksa jumlah argumen sesuai dengan parameter. Jika kamu memanggil fungsi tanpa argumen yang dibutuhkan, nilainya menjadi undefined dan perhitungan bisa menghasilkan NaN.
function kali(a, b) {
return a * b;
}
console.log(kali(5)); // NaN
Berikan nilai default pada parameter untuk menghindari masalah ini. Contoh: function kali(a, b = 1) { ... }. Kamu juga bisa memvalidasi argumen di awal fungsi jika nilainya menentukan hasil.
5. Mengubah objek argumen secara langsung
Objek yang dilewatkan ke fungsi diteruskan sebagai referensi. Jika fungsi mengubah properti objek tersebut, perubahan akan terlihat di luar fungsi. Ini sering tidak diinginkan, terutama saat fungsi seharusnya bersifat murni.
function tambahDiskon(produk) {
produk.harga = produk.harga * 0.9;
return produk;
}
const barang = { nama: 'Kaos', harga: 100000 };
tambahDiskon(barang);
console.log(barang.harga); // 90000, objek asli berubah
Buat salinan objek jika kamu perlu memodifikasinya tanpa efek samping: const baru = { ...produk, harga: produk.harga * 0.9 };. Untuk topik terkait penggabungan objek, kamu bisa membaca Menggabungkan Objek di JavaScript: Object.assign vs Spread.
6. Salah menggunakan return di dalam callback
Menempatkan return di dalam callback forEach tidak menghentikan iterasi. Banyak yang mengira return akan keluar dari loop, padahal itu hanya keluar dari fungsi callback.
[1, 2, 3].forEach(n => {
if (n === 2) return;
console.log(n); // 1 dan 3 tetap tercetak
});
Jika kamu perlu menghentikan iterasi lebih awal, gunakan loop for biasa atau metode array seperti some atau every yang memang mendukung penghentian. Pilihan metode iterasi dibahas lebih lanjut di Memilih Metode Iterasi Array di JavaScript: for, forEach, atau map?.
7. Mendeklarasikan fungsi di dalam blok tanpa memperhatikan hoisting
Fungsi yang dideklarasikan dengan function di dalam blok (seperti if atau for) memiliki perilaku hoisting yang berbeda-beda antar lingkungan. Dalam mode strict, deklarasi fungsi di dalam blok hanya berlaku di blok tersebut, tetapi di mode non-strict bisa bocor ke luar.
if (true) {
function sapa() {
console.log('Halo');
}
}
sapa(); // Bisa error atau berhasil tergantung lingkungan
Untuk menghindari ambiguitas, gunakan ekspresi fungsi yang ditugaskan ke variabel dengan const atau let, atau pindahkan deklarasi ke cakupan yang lebih luar jika memang diperlukan.
Ringkasan
Kesalahan dalam menulis fungsi JavaScript sering kali berasal dari detail kecil: lupa return, salah memahami this, atau mengira return di callback menghentikan loop. Dengan mengenali tujuh pola di atas, kamu bisa menulis fungsi yang lebih dapat diprediksi dan mudah dirawat. Uji fungsi dengan berbagai input, termasuk kasus tepi, untuk memastikan perilakunya sesuai harapan.
Pertanyaan yang Sering Diajukan
Mengapa fungsi saya mengembalikan undefined padahal sudah ada return?
Periksa apakah return berada di dalam blok kondisional yang tidak terpenuhi, atau mungkin kamu menulis return di dalam callback yang tidak dieksekusi. Pastikan juga tidak ada kesalahan ketik seperti retrun.
Apakah arrow function selalu lebih baik daripada function biasa?
Tidak selalu. Arrow function cocok untuk callback yang tidak membutuhkan this sendiri, tetapi untuk method objek atau konstruktor, function biasa lebih tepat karena arrow function tidak bisa digunakan dengan new dan tidak memiliki arguments.
Bagaimana cara menghindari efek samping saat memodifikasi objek di dalam fungsi?
Buat salinan objek sebelum memodifikasinya, misalnya dengan spread operator atau Object.assign. Dengan begitu, objek asli tetap aman dan fungsi menjadi lebih prediktabel.