Saya telah membaca banyak Javascript belakangan ini dan saya telah memperhatikan bahwa seluruh file dibungkus seperti berikut dalam file .js yang akan diimpor.
(function() {
...
code
...
})();
Apa alasan untuk melakukan ini daripada satu set fungsi konstruktor yang sederhana?
javascript
scope
coding-style
iife
Andrew Kou
sumber
sumber
Jawaban:
Biasanya untuk namespace (lihat nanti) dan mengontrol visibilitas fungsi anggota dan / atau variabel. Anggap saja seperti definisi objek. Nama teknis untuk itu adalah Ekspresi Fungsi Segera Dibawa (IIFE). Plugin jQuery biasanya ditulis seperti ini.
Di Javascript, Anda bisa membuat fungsi sarang. Jadi, yang berikut ini legal:
Sekarang Anda dapat menelepon
outerFunction()
, tetapi visiblityinnerFunction()
terbatas pada ruang lingkupouterFunction()
, yang berarti pribadiouterFunction()
. Ini pada dasarnya mengikuti prinsip yang sama dengan variabel dalam Javascript:Sejalan dengan itu:
Dalam skenario di atas, Anda dapat menelepon
globalFunction()
dari mana saja, tetapi Anda tidak dapat meneleponlocalFunction1
ataulocalFunction2
.Apa yang Anda lakukan saat menulis
(function() { ... })()
, adalah membuat kode di dalam set kurung pertama sebagai fungsi literal (artinya seluruh "objek" sebenarnya adalah sebuah fungsi). Setelah itu, Anda menjalankan sendiri fungsi (final()
) yang baru saja Anda tetapkan. Jadi keuntungan utama dari ini seperti yang saya sebutkan sebelumnya, adalah Anda dapat memiliki metode / fungsi dan properti pribadi:Pada contoh pertama, Anda akan secara eksplisit memanggil
globalFunction
nama untuk menjalankannya. Artinya, Anda hanya perlu melakukannyaglobalFunction()
untuk menjalankannya. Tetapi dalam contoh di atas, Anda tidak hanya mendefinisikan suatu fungsi; Anda mendefinisikan dan menjalankannya dalam sekali jalan. Ini berarti bahwa ketika file JavaScript Anda dimuat, segera dieksekusi. Tentu saja, Anda bisa melakukan:Perilaku ini sebagian besar akan sama kecuali untuk satu perbedaan signifikan: Anda menghindari mencemari ruang lingkup global ketika Anda menggunakan IIFE (sebagai akibatnya itu juga berarti bahwa Anda tidak dapat memanggil fungsi beberapa kali karena tidak memiliki nama, tetapi karena fungsi ini hanya dimaksudkan untuk dieksekusi setelah itu benar-benar bukan masalah).
Hal yang rapi dengan IIFE adalah bahwa Anda juga dapat mendefinisikan hal-hal di dalam dan hanya mengekspos bagian yang Anda inginkan ke dunia luar begitu (contoh namespacing sehingga Anda pada dasarnya dapat membuat perpustakaan / plugin Anda sendiri):
Sekarang Anda dapat menelepon
myPlugin.public_function1()
, tetapi Anda tidak dapat mengaksesprivate_function()
! Sangat mirip dengan definisi kelas. Untuk memahami ini dengan lebih baik, saya merekomendasikan tautan berikut untuk bacaan lebih lanjut:EDIT
Saya lupa menyebutkan. Di final itu
()
, Anda bisa melewati apa pun yang Anda inginkan di dalam. Misalnya, ketika Anda membuat plugin jQuery, Anda meneruskanjQuery
atau$
suka:Jadi yang Anda lakukan di sini adalah mendefinisikan fungsi yang mengambil satu parameter (disebut
jQ
, variabel lokal, dan hanya diketahui oleh fungsi itu). Kemudian Anda menjalankan fungsi sendiri dan mengirimkan parameter (juga disebutjQuery
, tetapi yang ini dari dunia luar dan referensi ke jQuery aktual itu sendiri). Tidak perlu mendesak untuk melakukan ini, tetapi ada beberapa keuntungan:Sebelumnya saya menjelaskan bagaimana fungsi-fungsi ini berjalan secara otomatis pada saat startup, tetapi jika mereka berjalan secara otomatis, siapa yang memberikan argumen? Teknik ini mengasumsikan bahwa semua parameter yang Anda butuhkan sudah didefinisikan sebagai variabel global. Jadi jika jQuery belum didefinisikan sebagai variabel global, contoh ini tidak akan berfungsi. Seperti yang Anda duga, satu hal yang dilakukan jquery.js saat inisialisasi adalah mendefinisikan variabel global 'jQuery', serta variabel global '$' yang lebih terkenal, yang memungkinkan kode ini berfungsi setelah jQuery dimasukkan.
sumber
;(function(jQ) { ... code ... })(jQuery);
Dengan cara ini jika seseorang meninggalkan tanda titik koma di skripnya, itu tidak akan menghancurkan Anda, terutama jika Anda berencana untuk memperkecil dan menyatukan skrip Anda dengan yang lain.(function (context) { ..... })(this)
yang kemudian memungkinkan Anda untuk melampirkan apa pun yang Anda suka ke konteks induk sehingga memaparkannya.Pendeknya
Ringkasan
Dalam bentuknya yang paling sederhana, teknik ini bertujuan untuk membungkus kode di dalam lingkup fungsi .
Ini membantu mengurangi kemungkinan:
Itu tidak mendeteksi ketika dokumen sudah siap - itu bukan semacam
document.onload
atau tidakwindow.onload
Umumnya dikenal sebagai
Immediately Invoked Function Expression (IIFE)
atauSelf Executing Anonymous Function
.Kode Dijelaskan
Dalam contoh di atas, variabel apa pun yang didefinisikan dalam fungsi (yaitu dideklarasikan menggunakan
var
) akan menjadi "pribadi" dan dapat diakses dalam lingkup fungsi HANYA (seperti yang dikatakan Vivin Paliath). Dengan kata lain, variabel-variabel ini tidak terlihat / terjangkau di luar fungsi. Lihat demo langsung .Javascript memiliki fungsi pelingkupan. "Parameter dan variabel yang didefinisikan dalam suatu fungsi tidak terlihat di luar fungsi, dan bahwa variabel yang didefinisikan di mana saja dalam suatu fungsi terlihat di mana-mana dalam fungsi." (dari "Javascript: The Good Parts").
Keterangan lebih lanjut
Kode Alternatif
Pada akhirnya, kode yang diposting sebelumnya juga dapat dilakukan sebagai berikut:
Lihat demo langsung .
Akar
Iterasi 1
Suatu hari, seseorang mungkin berpikir "pasti ada cara untuk menghindari penamaan 'myMainFunction', karena semua yang kita inginkan adalah menjalankannya dengan segera."
Jika Anda kembali ke dasar-dasarnya, Anda mengetahui bahwa:
expression
: sesuatu yang mengevaluasi suatu nilai. yaitu3+11/x
statement
: baris kode melakukan sesuatu TETAPI itu tidak mengevaluasi nilai. yaituif(){}
Demikian pula, ekspresi fungsi mengevaluasi suatu nilai. Dan satu konsekuensi (saya kira?) Adalah mereka dapat langsung dipanggil:
Jadi contoh kita yang lebih kompleks menjadi:
Lihat demo langsung .
Iterasi 2
Langkah selanjutnya adalah pikiran "mengapa
var myMainFunction =
kita harus menggunakan itu saja !?"Jawabannya sederhana: coba hapus ini, seperti di bawah ini:
Lihat demo langsung .
Ini tidak akan berfungsi karena "deklarasi fungsi tidak dapat dimasuki" .
Kuncinya adalah dengan menghapus
var myMainFunction =
kita mengubah ekspresi fungsi menjadi pernyataan fungsi . Lihat tautan di "Sumberdaya" untuk detail lebih lanjut tentang ini.Pertanyaan selanjutnya adalah "mengapa saya tidak bisa menyimpannya sebagai ekspresi fungsi dengan sesuatu selain
var myMainFunction =
?Jawabannya adalah "Anda bisa", dan sebenarnya ada banyak cara Anda bisa melakukan ini: menambahkan a
+
, a!
, a-
, atau mungkin membungkus sepasang tanda kurung (seperti yang sekarang dilakukan oleh konvensi), dan lebih banyak lagi saya percaya. Sebagai contoh:atau
atau
Jadi, setelah modifikasi yang relevan ditambahkan ke apa yang dulunya "Kode Alternatif" kami, kami kembali ke kode yang sama persis seperti yang digunakan dalam contoh "Kode Dijelaskan"
Baca lebih lanjut tentang
Expressions vs Statements
:Lingkup Demistifikasi
Satu hal yang mungkin bertanya-tanya adalah "apa yang terjadi ketika Anda TIDAK mendefinisikan variabel 'benar' di dalam fungsi - yaitu melakukan tugas sederhana sebagai gantinya?"
Lihat demo langsung .
Pada dasarnya, jika suatu variabel yang tidak dideklarasikan dalam lingkupnya saat ini diberi nilai, maka "lihat rantai lingkup terjadi sampai ia menemukan variabel atau mengenai lingkup global (pada titik mana ia akan membuatnya)".
Ketika di lingkungan browser (vs lingkungan server seperti nodejs) lingkup global ditentukan oleh
window
objek. Karenanya kita bisa melakukannyawindow.myOtherFunction()
.Kiat "Praktik yang baik" pada topik ini adalah untuk selalu digunakan
var
saat menentukan apa pun : apakah itu angka, objek, atau fungsi, & bahkan saat dalam lingkup global. Ini membuat kode lebih sederhana.catatan:
block scope
(Pembaruan: ruang lingkup variabel lokal ditambahkan dalam ES6 .)function scope
&global scope
(window
cakupan di lingkungan browser)Baca lebih lanjut tentang
Javascript Scopes
:Sumber daya
Langkah selanjutnya
Setelah Anda mendapatkan
IIFE
konsep ini , itu mengarah kemodule pattern
, yang biasanya dilakukan dengan memanfaatkan pola IIFE ini. Selamat bersenang-senang :)sumber
Javascript di browser hanya benar-benar memiliki beberapa cakupan efektif: lingkup fungsi dan ruang lingkup global.
Jika variabel tidak dalam lingkup fungsi, itu dalam lingkup global. Dan variabel global umumnya buruk, jadi ini adalah konstruksi untuk menjaga variabel perpustakaan untuk dirinya sendiri.
sumber
Itu disebut penutupan. Ini pada dasarnya menyegel kode di dalam fungsi sehingga perpustakaan lain tidak mengganggu itu. Ini mirip dengan membuat namespace dalam bahasa yang dikompilasi.
Contoh. Misalkan saya menulis:
Sekarang perpustakaan lain tidak dapat mengakses variabel yang
x
saya buat untuk digunakan di perpustakaan saya.sumber
(function(){ ... return { publicProp1: 'blah' }; })();
. Jelas tidak sejajar sempurna dengan namespace, tetapi mungkin membantu untuk memikirkannya seperti itu.Anda dapat menggunakan penutupan fungsi sebagai data dalam ekspresi yang lebih besar juga, seperti dalam metode ini menentukan dukungan browser untuk beberapa objek html5.
sumber
Selain menjaga variabel lokal, satu penggunaan yang sangat berguna adalah ketika menulis perpustakaan menggunakan variabel global, Anda bisa memberinya nama variabel yang lebih pendek untuk digunakan dalam perpustakaan. Ini sering digunakan dalam menulis plugin jQuery, karena jQuery memungkinkan Anda untuk menonaktifkan $ variabel yang menunjuk ke jQuery, menggunakan jQuery.noConflict (). Jika dinonaktifkan, kode Anda masih dapat menggunakan $ dan tidak rusak jika Anda hanya melakukannya:
sumber
sumber
Kita juga harus menggunakan 'gunakan ketat' dalam fungsi lingkup untuk memastikan bahwa kode harus dieksekusi dalam "mode ketat". Kode contoh ditunjukkan di bawah ini
sumber