Ada satu cara lagi untuk membuat suatu fungsi. Jarang digunakan, tapi terkadang tidak ada alternatif lain.
Sintaks untuk membuat suatu fungsi:
biarkan func = Fungsi baru ([arg1, arg2, ...argN], functionBody);
Fungsi ini dibuat dengan argumen arg1...argN
dan functionBody
yang diberikan.
Lebih mudah untuk memahaminya dengan melihat contoh. Inilah fungsi dengan dua argumen:
misalkan jumlah = Fungsi baru('a', 'b', 'mengembalikan a + b'); peringatan(jumlah(1, 2) ); // 3
Dan di sini ada fungsi tanpa argumen, hanya dengan isi fungsi:
misalkan sayHi = new Function('alert("Halo")'); sayHai(); // Halo
Perbedaan utama dari cara lain yang telah kita lihat adalah bahwa fungsi tersebut dibuat secara harfiah dari sebuah string, yang diteruskan pada saat run time.
Semua deklarasi sebelumnya mengharuskan kita, programmer, untuk menulis kode fungsi dalam skrip.
Tapi new Function
memungkinkan untuk mengubah string apa pun menjadi fungsi. Misalnya, kita bisa menerima fungsi baru dari server dan kemudian menjalankannya:
biarkan str = ... menerima kode dari server secara dinamis ... biarkan func = Fungsi baru(str); fungsi();
Ini digunakan dalam kasus yang sangat spesifik, seperti ketika kita menerima kode dari server, atau untuk mengkompilasi fungsi secara dinamis dari template, dalam aplikasi web yang kompleks.
Biasanya, suatu fungsi mengingat di mana ia dilahirkan di properti khusus [[Environment]]
. Ini merujuk pada Lingkungan Leksikal dari mana ia dibuat (kita membahasnya di bab Cakupan variabel, penutupan).
Namun ketika suatu fungsi dibuat menggunakan new Function
, [[Environment]]
-nya diatur untuk merujuk bukan pada Lingkungan Lexical saat ini, namun pada lingkungan global.
Jadi, fungsi tersebut tidak memiliki akses ke variabel luar, hanya ke variabel global.
fungsi getFunc() { biarkan nilai = "uji"; biarkan func = new Function('alert(nilai)'); fungsi pengembalian; } getFunc()(); // kesalahan: nilai tidak ditentukan
Bandingkan dengan perilaku biasa:
fungsi getFunc() { biarkan nilai = "uji"; biarkan func = function() { peringatan(nilai); }; fungsi pengembalian; } getFunc()(); // "test", dari Lingkungan Leksikal getFunc
Fitur khusus new Function
ini terlihat aneh, namun tampak sangat berguna dalam praktiknya.
Bayangkan kita harus membuat fungsi dari sebuah string. Kode fungsi tersebut tidak diketahui pada saat penulisan skrip (itulah sebabnya kami tidak menggunakan fungsi biasa), tetapi akan diketahui dalam proses eksekusi. Kami mungkin menerimanya dari server atau dari sumber lain.
Fungsi baru kita perlu berinteraksi dengan skrip utama.
Bagaimana jika ia dapat mengakses variabel luar?
Masalahnya adalah sebelum JavaScript dipublikasikan ke produksi, JavaScript dikompresi menggunakan minifier – program khusus yang mengecilkan kode dengan menghapus komentar tambahan, spasi, dan – yang penting, mengganti nama variabel lokal menjadi lebih pendek.
Misalnya, jika suatu fungsi memiliki let userName
, minifier menggantinya dengan let a
(atau huruf lain jika yang ini terisi), dan melakukannya di mana saja. Itu biasanya merupakan hal yang aman untuk dilakukan, karena variabelnya bersifat lokal, tidak ada apa pun di luar fungsi yang dapat mengaksesnya. Dan di dalam fungsinya, minifier menggantikan setiap penyebutannya. Minifier itu cerdas, mereka menganalisis struktur kode, sehingga tidak merusak apa pun. Mereka bukan hanya sekedar mencari dan mengganti yang bodoh.
Jadi, jika new Function
memiliki akses ke variabel luar, Fungsi tersebut tidak akan dapat menemukan userName
yang diganti namanya.
Jika new Function
memiliki akses ke variabel luar, maka akan ada masalah dengan minifier.
Selain itu, kode seperti itu secara arsitektural buruk dan rentan terhadap kesalahan.
Untuk meneruskan sesuatu ke suatu fungsi, yang dibuat sebagai new Function
, kita harus menggunakan argumennya.
Sintaksnya:
biarkan func = Fungsi baru ([arg1, arg2, ...argN], functionBody);
Karena alasan historis, argumen juga dapat diberikan dalam bentuk daftar yang dipisahkan koma.
Ketiga deklarasi ini memiliki arti yang sama:
Fungsi baru('a', 'b', 'mengembalikan a + b'); // sintaks dasar Fungsi baru('a,b', 'mengembalikan a + b'); // dipisahkan koma Fungsi baru('a, b', 'mengembalikan a + b'); // dipisahkan koma dengan spasi
Fungsi yang dibuat dengan new Function
, memiliki [[Environment]]
yang merujuk pada Lingkungan Leksikal global, bukan lingkungan luar. Oleh karena itu, mereka tidak dapat menggunakan variabel luar. Tapi itu sebenarnya bagus, karena menjamin kita dari kesalahan. Melewati parameter secara eksplisit adalah metode arsitektur yang jauh lebih baik dan tidak menyebabkan masalah dengan minifier.