Javascript adalah bahasa yang berorientasi-fungsi. Itu memberikan kita banyak kebebasan. Sebuah fungsi bisa dibuat kapanpun, diberikan sebagai argumen kedalam fungsi lain, dan lalu dipanggil dari kode yang benar-benar berbeda nanti.
Kita sudah tahu bahwa sebuah fungsi bisa mengakses variabel diluar dari fungsi tersebut (variabel “luar”).
Tapi apa yang terjadi jika variabel luar berubah saat fungsinya dibuat? Akankan fungsinya mendapatkan nilai yang baru atau yang lama?
Dan bagaimana jika sebuah fungsi diberikan sebagai paramter dan dipanggil dibagian kode lain, akankah itu mendapatkan akses ke variabel luar ditempat itu?
Ayo kita peruas pengetahuan kita untuk mengerti skenario ini dan skenario yang lebih kompleks.
let/const di siniDi JavaScript, ada 3 cara mendeklarasi variabel: let, const (cara-cara modern), dan var (sisa masa lalu).
- Di artikel ini kita akan memakai variabel
letdalam contoh. - Variabel, yang dideklarasi dengan
const, bertindak sama, jadi artikel ini juga tentangconst. varusang punya perbedaan mencolok, mereka akan dibahas di artikel Si Tua "var".
Blok kode
Jika variabel dideklarasi di dalam blok kode {...}, ia hanya terlihat di dalam blok itu.
Misalnya:
{
// lakukan pekerjaan dengan variabel lokal yang harusnya tak terlihat dari luar
let message = "Hello"; // hanya terlihat dalam blok ini
alert(message); // Hello
}
alert(message); // Error: message is not defined
Kita bisa memakai ini untuk mengisolasi potongan kode yang melakukan tugasnya sendiri, dengan variabel yang dia punya sendiri:
{
// tampilkan pesan
let message = "Hello";
alert(message);
}
{
// tampilkan pesan lain
let message = "Goodbye";
alert(message);
}
Tolong ingat, tanpa blok terpisah akan muncul galat, jika kita memakai let dengan nama variabel yang sudah ada:
// tampilkan pesan
let message = "Hello";
alert(message);
// tampilkan pesan lain
let message = "Goodbye"; // Galat: variabel sudah dideklarasi
alert(message);
Untuk if, for, while dan lain-lain, variabel yang dideklarasi dalam {...} juga hanya terlihat di situ saja:
if (true) {
let phrase = "Hello!";
alert(phrase); // Hello!
}
alert(phrase); // Galat, variabel ini tak ada!
Di sini, setelah if selesai, alert di bawah tak akan melihat phrase, sehingga terjadi galat.
Ini keren, karena ia memperbolehkan kita membuat variabel blok-lokal, yang spesifik ke cabang if.
Hal serupa juga berlaku untuk loop for dan while:
for (let i = 0; i < 3; i++) {
// variabel i hanya terlihat di dalam for ini
alert(i); // 0, lalu 1, lalu 2
}
alert(i); // Galat, variabel ini tak ada
Visually, let i is outside of {...}. But the for construct is special here: the variable, declared inside it, is considered a part of the block.
Fungsi bersarang
Sebuah fungsi dikatakan “bersarang” apabila fungsi tersebut dibuat di dalam fungsi lainnya.
Hal tersebut mudah untuk dilakukan di JavaScript.
Kita dapat melakukannya untuk mengatur kode kita, seperti ini:
function sayHiBye(firstName, lastName) {
// fungsi pembantu untuk digunakan di bawah
function getFullName() {
return firstName + " " + lastName;
}
alert( "Hello, " + getFullName() );
alert( "Bye, " + getFullName() );
}
Di sini fungsi bersarang dibuat untuk kemudahan. Fungsi tersebut bisa mengakses variabel luar sehingga dapat mengembalikan nama lengkap. Fungsi bersarang cukup sering ditemui di JavaScript.
Yang lebih menarik yaitu, fungsi bersarang dapat dikembalikan: bisa sebagai properti dari objek baru atau sebagai nilai kembalian itu sendiri. Nilai kembalian tersebut bisa dipakai di tempat lain. Tak peduli di mana, ia masih punya akses ke variabel luar yang sama.
Di bawah ini, makeCounter membuat fungsi “counter” yang mengembalikan angka berikutnya di tiap invokasi:
function makeCounter() {
let count = 0;
return function() {
return count++;
};
}
let counter = makeCounter();
alert( counter() ); // 0
alert( counter() ); // 1
alert( counter() ); // 2
Meski sederhana, varian kode itu yang sedikit dimodifikasi punya kegunaan praktis, misalnya, sebagai generator angka random untuk menggenerate nilai random untuk tes terotomasi.
How does this work? If we create multiple counters, will they be independent? What’s going on with the variables here?
Memahami hal begini bagus untuk pengetahuan keseluruhan JavaScript dan menguntungkan untuk skenario yang lebih komplex. Jadi ayo kita selami lebih dalam.
Lingkungan Lexikal
Penjelasan teknikal mendalam ada di depan.
Semakin jauh aku menghindari detil bahasa level-rendah, pemahaman apapun tanpa mereka akan kekurangan dan tak-lengkap, jadi bersiaplah.
Supaya jelas, penjelasan dibagi dalam beberapa langkah.
Langkah 1. Variabel
Di JavaScript, setiap fungsi yang berjalan, blok kode {...}, dan satu script yang menyeluruh punya objek internal (tersembunyi) yang terasosiasi yang dikenal dengan Lingkungan Lexikal.
Objek Lingkungan Lexikal punya dua bagian:
- Rekaman Lingkungan – objek yang menyimpan semua variabel lokal sebagai propertinya (dan beberapa informasi lain seperti nilai
this). - Referensi ke lingkungan lexikal luar, yang terasosiasi dengan kode luar.
“Variabel” cuma suatu properti dari objek internal spesial, Rekaman Lingkungan. “Untuk memperoleh atau mengganti variabel” berarti “memperoleh atau mengganti properti dari objek itu”.
Di kode sederhana tanpa fungsi ini, cuma ada satu Lingkugan Lexikal:
Ini yang disebut Lingkungan Lexikal global, terasosiasi dengan script keseluruhan.
Di gambar di atas, kotak persegi panjang artinya Rekaman Lingkungan (simpanan variabel) dan panah artinya referensi luar. Lingkungan Lexikal global tak punya referensi luar, itulah kenapa panahnya menunjuk ke null.
Seiring kodenya mulai bereksekusi dan berjalan, Lingkungan Lexikal berganti.
Ini kode yang sedikit lebih panjang:
Kotak persegi panjang di sisi kanan mendemonstrasikan bagaimana Lingkungan Lexikal global berganti selama exekusi:
- Ketika script berjalan, Lingkungan Lexikal di-pre-populasi dengan semua variabel yang terdeklarasi.
- Awalnya, mereka di state “Belum terinisialisir”. Itu state internal spesial, yang berarti bahwa engine tahu tentang variabelnya, tapi tak akan mengijinkan penggunaan itu sebelum
let. Ini hampir sama saja dengan variabel itu tak ada.
- Awalnya, mereka di state “Belum terinisialisir”. Itu state internal spesial, yang berarti bahwa engine tahu tentang variabelnya, tapi tak akan mengijinkan penggunaan itu sebelum
- Lalu definisi
let phrasemuncul. Tak ada penetapan dulu, jadi nilainyaundefined