Ringkasan
Bisakah Anda menjelaskan alasan di balik sintaks untuk fungsi anonim yang dienkapsulasi dalam JavaScript? Mengapa ini bekerja: (function(){})();
tetapi ini tidak function(){}();
:?
Apa yang saya tahu
Dalam JavaScript, seseorang membuat fungsi bernama seperti ini:
function twoPlusTwo(){
alert(2 + 2);
}
twoPlusTwo();
Anda juga dapat membuat fungsi anonim dan menetapkannya ke variabel:
var twoPlusTwo = function(){
alert(2 + 2);
};
twoPlusTwo();
Anda dapat merangkum satu blok kode dengan membuat fungsi anonim, lalu membungkusnya dalam tanda kurung dan langsung mengeksekusinya:
(function(){
alert(2 + 2);
})();
Ini berguna ketika membuat skrip termodulasi, untuk menghindari kekacauan lingkup saat ini, atau cakupan global, dengan variabel yang berpotensi bertentangan - seperti dalam kasus skrip Greasemonkey, plugin jQuery, dll.
Sekarang, saya mengerti mengapa ini berhasil. Tanda kurung melampirkan konten dan hanya memperlihatkan hasilnya (saya yakin ada cara yang lebih baik untuk menggambarkan itu), seperti dengan (2 + 2) === 4
.
Apa yang tidak saya mengerti
Tapi saya tidak mengerti mengapa ini tidak bekerja sama baiknya:
function(){
alert(2 + 2);
}();
Bisakah Anda menjelaskannya kepada saya?
sumber
Jawaban:
Ini tidak berfungsi karena sedang diuraikan sebagai
FunctionDeclaration
, dan pengidentifikasi nama deklarasi fungsi adalah wajib .Ketika Anda mengelilinginya dengan tanda kurung itu dievaluasi sebagai
FunctionExpression
, dan ekspresi fungsi dapat dinamai atau tidak.Tata bahasanya
FunctionDeclaration
terlihat seperti ini:Dan
FunctionExpression
s:Karena Anda dapat melihat token
Identifier
(Identifier opt )FunctionExpression
opsional, oleh karena itu kami dapat memiliki ekspresi fungsi tanpa nama yang ditentukan:Atau yang bernama ekspresi fungsi:
Tanda kurung (secara resmi disebut Pengelompokan Operator ) hanya dapat mengelilingi ekspresi, dan ekspresi fungsi dievaluasi.
Dua produksi tata bahasa bisa ambigu, dan mereka dapat terlihat persis sama, misalnya:
Parser tahu apakah itu a
FunctionDeclaration
atau aFunctionExpression
, tergantung pada konteks di mana ia muncul.Dalam contoh di atas, yang kedua adalah ekspresi karena operator Koma juga dapat menangani hanya ekspresi.
Di sisi lain,
FunctionDeclaration
s sebenarnya hanya dapat muncul dalam apa yang disebut "Program
" kode, artinya kode di luar dalam lingkup global, dan di dalamFunctionBody
fungsi-fungsi lainnya.Fungsi di dalam blok harus dihindari, karena dapat menyebabkan perilaku yang tidak terduga, misalnya:
Kode di atas seharusnya benar-benar menghasilkan a
SyntaxError
, karena aBlock
hanya dapat berisi pernyataan (dan Spesifikasi Naskah ECMAS tidak mendefinisikan pernyataan fungsi apa pun), tetapi sebagian besar implementasi bersifat toleran, dan hanya akan mengambil fungsi kedua, yang diperingatkan'false!'
.Implementasi Mozilla -Rhino, SpiderMonkey, - memiliki perilaku yang berbeda. Tata bahasa mereka mengandung Pernyataan Fungsi non-standar , yang berarti bahwa fungsi tersebut akan dievaluasi pada saat run-time , bukan pada waktu parse, seperti yang terjadi pada
FunctionDeclaration
s. Dalam implementasi tersebut kita akan mendefinisikan fungsi pertama.Fungsi dapat dideklarasikan dengan cara yang berbeda, bandingkan yang berikut :
1- Fungsi yang didefinisikan dengan konstruktor Fungsi yang ditugaskan ke variabel multiply :
2- Deklarasi fungsi dari suatu fungsi bernama multiply :
3- Ekspresi fungsi yang ditugaskan ke variabel multiply :
4- Nama fungsi func_name ekspresi , ditugaskan untuk variabel multiply :
sumber
Meskipun ini adalah pertanyaan dan jawaban lama, ini membahas topik yang hingga hari ini banyak dilemparkan pengembang untuk loop. Saya tidak bisa menghitung jumlah kandidat pengembang JavaScript yang saya wawancarai yang tidak bisa memberi tahu saya perbedaan antara deklarasi fungsi dan ekspresi fungsi dan yang tidak tahu apa itu ekspresi fungsi yang segera dipanggil.
Saya ingin menyebutkan, satu hal yang sangat penting yaitu potongan kode Premasagar tidak akan berfungsi bahkan jika dia memberinya pengenal nama.
Alasan ini tidak berhasil adalah bahwa mesin JavaScript mengartikan ini sebagai deklarasi fungsi diikuti oleh operator pengelompokan yang sama sekali tidak terkait yang tidak mengandung ekspresi, dan operator pengelompokan harus berisi ekspresi. Menurut JavaScript, potongan kode di atas setara dengan yang berikut.
Hal lain yang ingin saya tunjukkan yang mungkin bermanfaat bagi sebagian orang adalah bahwa pengenal nama apa pun yang Anda berikan untuk ekspresi fungsi cukup berguna dalam konteks kode kecuali dari dalam definisi fungsi itu sendiri.
Tentu saja, menggunakan pengidentifikasi nama dengan definisi fungsi Anda selalu membantu ketika datang ke kode debugging, tapi itu sesuatu yang sama sekali berbeda ... :-)
sumber
Jawaban yang bagus sudah diposting. Tapi saya ingin mencatat bahwa deklarasi fungsi mengembalikan catatan penyelesaian kosong:
Fakta ini tidak mudah untuk diamati, karena sebagian besar cara mencoba untuk mendapatkan nilai yang dikembalikan akan mengkonversi deklarasi fungsi ke ekspresi fungsi. Namun,
eval
perlihatkan:Memanggil catatan penyelesaian kosong tidak masuk akal. Itu sebabnya
function f(){}()
tidak bisa bekerja. Bahkan mesin JS bahkan tidak berusaha menyebutnya, tanda kurung dianggap sebagai bagian dari pernyataan lain.Tetapi jika Anda membungkus fungsi dalam tanda kurung, itu menjadi ekspresi fungsi:
Ekspresi fungsi mengembalikan objek fungsi. Dan karena itu Anda dapat menyebutnya:
(function f(){})()
.sumber
Dalam javascript, ini disebut Immediately-Invoked Function Expression (IIFE) .
Untuk menjadikannya ekspresi fungsi, Anda harus:
lampirkan menggunakan ()
letakkan operator batal sebelum itu
tetapkan ke variabel.
Kalau tidak, itu akan diperlakukan sebagai definisi fungsi dan kemudian Anda tidak akan dapat memanggil / memanggilnya secara bersamaan dengan cara berikut:
Di atas akan memberi Anda kesalahan. Karena Anda hanya dapat menjalankan ekspresi fungsi dengan segera.
Ini dapat dicapai dengan beberapa cara: Cara 1:
Cara 2:
Cara 3:
cara 4:
Semua di atas akan segera memanggil ekspresi fungsi.
sumber
Saya hanya punya sedikit komentar. Kode Anda akan berfungsi dengan perubahan kecil:
Saya menggunakan sintaks di atas dan bukan versi yang lebih luas:
karena saya tidak berhasil mendapatkan indentasi agar berfungsi dengan benar untuk file javascript di vim. Tampaknya vim tidak suka kurung kurawal di dalam kurung buka.
sumber
function
kata kunci sebagai deklarasi fungsi dalam hal ini trailing()
ditafsirkan sebagai operator pengelompokan yang, menurut aturan sintaksis JavaScript, hanya dapat dan harus berisi ekspresi JavaScript.()
terlampir dalam operator pengelompokan (yang sangat direkomendasikan oleh Douglas Crockford) untuk konsistensi: itu umum untuk menggunakan IIFE tanpa menugaskan mereka ke variabel, dan mudah untuk lupa menyertakan kurung kurung itu jika Anda tidak menggunakannya secara konsisten.Mungkin jawaban yang lebih pendek adalah itu
adalah fungsi literal yang mendefinisikan fungsi (anonim). Pasangan () tambahan, yang ditafsirkan sebagai ekspresi, tidak diharapkan pada tingkat atas, hanya literal.
ada dalam pernyataan ekspresi yang memanggil fungsi anonim.
sumber
Di atas adalah sintaks yang valid karena apa pun yang disampaikan di dalam tanda kurung dianggap sebagai ekspresi fungsi.
Di atas bukan sintaks yang valid. Karena java script syntax parser mencari nama fungsi setelah kata kunci fungsi karena tidak menemukan apa-apa itu membuat kesalahan.
sumber
Anda juga dapat menggunakannya seperti:
atau
!
- negasi op mengonversi definisi fn ke ekspresi fn, oleh karena itu, Anda dapat langsung memohonnya()
. Sama seperti menggunakan0,fn def
atauvoid fn def
sumber
Mereka dapat digunakan dengan parameter-argumen seperti
akan menghasilkan 7
sumber
Tanda kurung ekstra tersebut menciptakan fungsi anonim tambahan antara namespace global dan fungsi anonim yang berisi kode. Dan dalam fungsi-fungsi Javascript yang dinyatakan di dalam fungsi-fungsi lain hanya dapat mengakses namespace dari fungsi induk yang berisi mereka. Karena ada objek tambahan (fungsi anonim) antara ruang lingkup global dan pelingkupan kode aktual tidak dipertahankan.
sumber