Lokasi tanda kurung untuk menjalankan fungsi JavaScript anonim secara otomatis?

107

Saya baru-baru ini membandingkan versi json2.js saat ini dengan versi yang saya miliki di proyek saya dan melihat perbedaan dalam cara ekspresi fungsi dibuat dan dijalankan sendiri.

Kode yang digunakan untuk membungkus fungsi anonim dalam tanda kurung dan kemudian menjalankannya,

(function () {
  // code here
})();

tapi sekarang ini membungkus fungsi yang dieksekusi secara otomatis dalam tanda kurung.

(function () {
  // code here
}());

Ada komentar dari CMS dalam jawaban yang diterima dari Jelaskan sintaks fungsi anonim yang dienkapsulasi JavaScript bahwa "keduanya: (function(){})();dan (function(){}());valid."

Saya bertanya-tanya apa bedanya? Apakah yang pertama mengambil memori dengan meninggalkan fungsi global dan anonim? Di mana lokasi tanda kurung?

Kevin Hakanson
sumber
Terkait: Sintaks pemanggilan fungsi langsung (dalam JSLint)
Bergi
1
Juga membaca tentang tujuan konstruk ini , atau cek ( teknis ) penjelasan (juga di sini ). Untuk mengapa tanda kurung diperlukan, lihat pertanyaan ini .
Bergi

Jawaban:

66

Mereka hampir sama.

Yang pertama membungkus tanda kurung di sekitar fungsi untuk membuatnya menjadi ekspresi yang valid dan memanggilnya. Hasil ekspresi tidak ditentukan.

Yang kedua menjalankan fungsi dan tanda kurung di sekitar pemanggilan otomatis menjadikannya ekspresi yang valid. Ini juga mengevaluasi ke tidak terdefinisi.

Saya rasa tidak ada cara yang "benar" untuk melakukannya, karena hasil ungkapannya sama.

> function(){}()
SyntaxError: Unexpected token (
> (function(){})()
undefined
> (function(){return 'foo'})()
"foo"
> (function(){ return 'foo'}())
"foo"
meder omuraliev
sumber
8
JSLint menginginkan "(function () {} ());". JSLint mengatakan, "Pindahkan pemanggilan ke dalam tanda kurung yang berisi fungsi."
XP1
27
Sebenarnya Anda tidak terbatas pada keduanya, Anda dapat menggunakan apa saja yang membuat kompiler menyadari bahwa fungsi tersebut adalah bagian dari ekspresi dan bukan pernyataan, seperti +function(){}()atau !function(){}().
Tgr
49
@ XP1: JSLint menginginkan banyak hal yang spesifik untuk gaya Crockford daripada yang substantif. Ini salah satunya.
TJ Crowder
@TJ. Apa yang akan Anda rekomendasikan? jQuery menggunakan gaya pertama dan Crockford menggunakan gaya kedua.
Teej
4
@ThorpeObazee: Ini benar-benar tidak masalah, jadi lakukan apa pun yang Anda suka. Saya akan merekomendasikan terhadap beberapa yang lebih aneh ( -function(){}();,, !function(){}();dan pada dasarnya semua operator lain sebelum functionjuga berfungsi, tetapi saya akan tetap menggunakan versi menggunakan parens). Saya melihat yang pertama lebih banyak daripada yang kedua, dan itu adalah preferensi saya; itu lebih masuk akal bagi saya juga, tapi itu subjektif. FWIW: jsbin.com/ejaqow
TJ Crowder
13

Dalam hal ini tidak masalah. Anda memanggil ekspresi yang menyelesaikan fungsi di definisi pertama, dan menentukan serta segera memanggil fungsi di contoh kedua. Mereka serupa karena ekspresi fungsi pada contoh pertama hanyalah definisi fungsi.

Ada kasus lain yang lebih jelas berguna untuk memanggil ekspresi yang menyelesaikan fungsi:

(foo || bar)()
Triptych
sumber
3
Untuk klarifikasi kepada pembaca lain (terutama karena saya sendiri awalnya tidak memahaminya :)), foo dan / atau bar pasti sudah sama dengan beberapa fungsi. (mis foo = function(){alert('hi');}. Jika tidak ada fungsi, kesalahan dilemparkan.
Alexander Bird
3
@AlexanderBird Klarifikasi lebih lanjut - Ini juga akan menimbulkan kesalahan jika foo"benar" tetapi bukan fungsi.
JLRishe
9

Tidak ada perbedaan di luar sintaks.

Mengenai kekhawatiran Anda tentang metode kedua untuk melakukannya:

Mempertimbangkan:

(function namedfunc () { ... }())

namedfunctidak akan berada dalam cakupan global meskipun Anda memberikan namanya. Hal yang sama berlaku untuk fungsi anonim. Satu-satunya cara untuk mendapatkannya dalam ruang lingkup itu adalah dengan menugaskannya ke variabel di dalam tanda kurung.

((namedfunc = function namedfunc () { ... })())

Tanda kurung luar tidak diperlukan:

(namedfunc = function namedfunc () { ... })()

Tapi Anda tidak menginginkan deklarasi global itu, bukan?

Jadi intinya adalah:

(function namedfunc () { ... })()

Dan Anda dapat menguranginya lebih jauh: nama tersebut tidak diperlukan karena tidak akan pernah digunakan (kecuali fungsi Anda rekursif .. dan bahkan Anda dapat menggunakannya arguments.callee)

(function () { ... })()

Begitulah cara saya memikirkannya (mungkin salah, saya belum membaca spesifikasi ECMAScript). Semoga membantu.

Cristian Sanchez
sumber
Perhatikan bahwa arguments.calleetidak digunakan lagi sejak ES5 (dan dilarang dalam mode ketat).
nyuszika7h
"Tanda kurung luar tidak diperlukan:" - Saya pikir mereka mencegah kesalahan saat file digabungkan, jika tidak, Anda memerlukan! atau sesuatu.
Jimmyt1988
-3

Perbedaannya hanya ada karena Douglas Crockford tidak menyukai gaya pertama untuk IIFE ! (seriuosly) Seperti yang Anda lihat di video ini !! .

Satu-satunya alasan keberadaan pembungkusan ekstra (){di kedua gaya} adalah untuk membantu membuat bagian kode Ekspresi Fungsi , karena Deklarasi Fungsi tidak bisa langsung dipanggil. Beberapa script / mengecilkan-ers hanya digunakan +, !, -& ~bukannya terlalu kurung. Seperti ini:

+function() {  
    var foo = 'bar';  
}();

!function() {  
    var foo = 'bar';  
}();

-function() {  
    var foo = 'bar';  
}();

~function() {  
    var foo = 'bar';  
}();

Dan semua ini persis sama dengan alternatif Anda. Memilih di antara kasus-kasus ini sepenuhnya Anda sendiri & tidak ada bedanya. {Yang ()menghasilkan 1 Byte File lebih besar ;-)}

behradkhodayar
sumber