fungsi javascript terkemuka bang! sintaksis

204

Saya telah melihat sintaks ini di beberapa perpustakaan sekarang dan saya bertanya-tanya apa manfaatnya. (perhatikan saya sangat mengetahui penutupan dan apa yang dilakukan kode, saya hanya peduli tentang perbedaan sintaksis)

!function(){
  // do stuff
}();

Sebagai alternatif yang lebih umum

(function(){
  // do stuff
})();

untuk memanggil sendiri fungsi anonim.

Saya ingin tahu beberapa hal. Pertama, apa yang membuat contoh teratas benar-benar berfungsi? Mengapa bang diperlukan untuk membuat pernyataan ini benar secara sintaksis? Saya juga diberitahu bahwa itu +berhasil, dan saya yakin beberapa orang lain, sebagai pengganti!

Kedua, apa manfaatnya? Yang bisa saya katakan adalah bahwa itu menghemat satu karakter, tetapi saya tidak bisa membayangkan itu manfaat yang sangat besar untuk menarik banyak pengguna. Apakah ada manfaat lain yang saya lewatkan?

Satu-satunya perbedaan lain yang dapat saya lihat adalah nilai balik dari fungsi pemanggilan sendiri, tetapi dalam kedua contoh ini, kami tidak terlalu peduli dengan nilai pengembalian fungsi karena hanya digunakan untuk membuat penutupan. Jadi, bisakah seseorang memberi tahu saya mengapa orang mungkin menggunakan sintaks pertama?

brad
sumber
Kerangka kerja suka menyimpan sebanyak mungkin karakter yang tidak bisa dioptimalkan oleh minifier.
alex
Manfaat pertama yang muncul di kepala saya adalah Anda dapat membuat kotak pasir seperti, (function ($) {...}) (jQuery);
JS Taylor
2
kedua contoh mencapai ini. Seperti yang disebutkan, saya mengerti apa fungsi ini lakukan, saya lebih tertarik pada perbedaan sintaksis
brad
8
Saya mengaitkannya dengan kebutuhan, nee, persyaratan untuk menjadi imut dengan cara yang lebih canggih dari kru sebelumnya. "Oh, orang-orang kafir itu, kita punya !!"
Jared Farrish
2
Saya tidak pernah tahu tentang ini, luar biasa. Saya suka !karena menekankan sedang dieksekusi.
cdmckay

Jawaban:

97

Idealnya Anda bisa melakukan semua ini hanya dengan:

function(){
  // do stuff
}(); 

Itu berarti mendeklarasikan fungsi anonim dan menjalankannya. Tapi itu tidak akan berhasil karena spesifikasi tata bahasa JS.

Jadi bentuk terpendek untuk mencapai ini adalah dengan menggunakan beberapa ekspresi misalnya UnaryExpression (dan CallExpression):

!function(){
  // do stuff
}(); 

Atau untuk bersenang-senang:

-function(){
  // do stuff
}(); 

Atau:

+function(){
  // do stuff
}(); 

Atau bahkan:

~function(){
  // do stuff
  return 0;
}( );
c-senyum
sumber
3
Jadi satu - satunya manfaat dari kesederhanaan?
brad
12
Saya telah menambahkan semua opsi di atas ke tes kinerja di: jsperf.com/bang-function
Shaz
5
Ekspresif saya akan mengatakan. Kecepatan tidak terlalu penting dalam kasus seperti itu karena dijalankan sekali.
c-smile
1
Karena penasaran, saya perhatikan bahwa tidak ada bang dan bang melakukan yang tercepat tetapi di suatu tempat dalam evolusi Chrome setidaknya, bang menjadi lebih cepat daripada tidak ada bang. (Mungkin secara statistik tidak signifikan tetapi ...) Apakah ada alasan mengapa? Saya tidak tahu banyak tentang kode di bawah tenda tetapi merasa cukup menarik.
jmk2142
Dua operator unary Anda dapat diartikan sebagai biner jika titik koma hilang. Yang pertama dan terakhir adalah yang paling aman dari contoh-contoh itu.
73

Dalam Javascript, garis yang dimulai dengan functiondiharapkan menjadi pernyataan fungsi dan seharusnya terlihat seperti

function doSomething() {
}

Seperti fungsi self-invaging

function(){
  // do stuff
}();

tidak cocok dengan formulir itu (dan akan menyebabkan kesalahan sintaks pada paren pembuka pertama karena tidak ada nama fungsi), sehingga tanda kurung digunakan untuk menggambarkan ekspresi fungsi anonim .

(function(){
  // do stuff
})();

Tetapi apa pun yang menciptakan ekspresi (sebagai lawan dari pernyataan fungsi) akan dilakukan, maka dari itu !. Ia memberi tahu juru bahasa bahwa ini bukan pernyataan fungsi. Selain itu, prioritas operator menentukan bahwa fungsi dipanggil sebelum negasi.

Saya tidak mengetahui tentang konvensi ini, tetapi jika menjadi umum konvensi ini dapat berkontribusi pada keterbacaan. Yang saya maksudkan adalah bahwa siapa pun yang membaca !functiondi bagian atas blok kode besar akan mengharapkan doa diri sendiri, cara kita dikondisikan untuk mengharapkan hal yang sama ketika kita melihat (function. Kecuali bahwa kita akan kehilangan tanda kurung yang mengganggu itu. Saya berharap itulah alasannya, berbeda dengan penghematan dalam hal kecepatan atau karakter.

brainjam
sumber
"Baris yang diawali dengan fungsi ini diharapkan ..." terlihat cukup kabur. Bagaimana dengan ini:var foo = {CR/LF here} function bar() {}
c-smile
45

Selain hal-hal yang sudah dikatakan, sintaks dengan! berguna jika Anda menulis javascript tanpa tanda titik koma:

var i = 1
!function(){
  console.log('ham')
}()

i = 2
(function(){
  console.log('cheese')
})()

Contoh pertama menghasilkan 'ham' seperti yang diharapkan, tetapi yang kedua akan menghasilkan kesalahan karena pernyataan i = 2 tidak dihentikan karena tanda kurung berikut.

Juga dalam file javascript bersambung Anda tidak perlu khawatir jika kode sebelumnya telah kehilangan titik koma. Jadi tidak perlu sama; (fungsi () {}) (); untuk memastikan milikmu tidak akan pecah.

Saya tahu jawaban saya agak terlambat tapi saya pikir itu belum disebutkan :)

Smoe
sumber
6
Memberi +1 untuk tip dan kenangan ... tidak ada yang suka menulis javascript tanpa titik koma hari ini.
Pablo Grisafi
4
Twitter Bootstrap adalah semua JS tanpa tanda titik koma, dan ini cukup baru ... (maaf jika komentar di atas sifatnya sarkastik dan saya melewatkannya).
brandwaffle
2
Ini sebenarnya tidak benar. Perhatikan contoh berikut:! Function () {console.log ("ham");} ()! Function () {console.log ("cheese")} (); Anda mendapatkan kesalahan: "SyntaxError: Token tak terduga!"
heavysixer
Ya kamu benar. Ada kesalahan, jika Anda meletakkannya di baris yang sama. Saya tidak memikirkan hal itu. Tapi, tidak ada naskah gabungan / lib yang saya gunakan sejauh ini. Dan ketika Anda mengecilkan & menyatukan file Anda, koma ditambahkan. Jadi, jujur, saya tidak bisa membayangkan kasus di mana Anda akan mengalami masalah itu. Di sisi lain, ini jam 2 pagi di sini dan saya mungkin bodoh :)
Smoe
6

Untuk satu hal, jsPerf menunjukkan bahwa menggunakan !(UnaryExpression) biasanya lebih cepat. Kadang-kadang mereka keluar untuk menjadi sama, tetapi ketika mereka tidak, saya belum melihat non-menggedor satu kemenangan terlalu banyak atas yang lain belum: http://jsperf.com/bang-function

Ini diuji pada Ubuntu terbaru dengan Chrome tertua (per katakan ..), versi 8. Jadi hasilnya tentu saja berbeda.

Sunting: Bagaimana dengan sesuatu yang gila delete?

delete function() {
   alert("Hi!"); 
}();

atau void?

void function() {
   alert("Hi!"); 
}();
Shaz
sumber
menarik! Saya mendapat sekitar 50/50 meskipun dalam Safari kecepatan-bijaksana, non-banged tentu dimiliki sendiri. Saya bertanya-tanya apakah ada beberapa teori tentang perbedaan kecepatan potensial?
brad
@brad Pasti ada hubungannya dengan safari, jika Anda melihat tes, sebagian besar browser lain tampaknya lebih disukai !. Tetapi saya juga ingin menemukan teori tentang hal ini :)
Shaz
3
saya suka batal karena secara eksplisit mengatakan "saya tidak peduli tentang nilai pengembalian", dan karena itu mengingatkan saya pada konvensi dalam bahasa lain
code_monk
4

Seperti yang Anda lihat di sini , cara terbaik untuk melakukan metode self-invoked dalam javascript menggunakan:

(function(){}()); -> 76,827,475 ops/sec

!function(){}();  -> 69,699,155 ops/sec

(function(){})(); -> 69,564,370 ops/sec
Geku
sumber
1
Saya ragu kinerja adalah alasan untuk menggunakan satu sintaks atau yang lain. Pada 70M ops / detik, mendeklarasikan penutupan akan menjadi ribuan kali lebih cepat daripada kode di dalam
Eloims
3

Jadi, dengan meniadakan "!" dan semua operator unary lainnya seperti +, -, ~, delete, void, banyak yang telah diberitahu, hanya untuk meringkas:

!function(){
  alert("Hi!");
}(); 

Atau

void function(){
  alert("Hi!");
}();

Atau

delete function(){
  alert("Hi!");
}();

Dan beberapa kasus lagi dengan operator biner untuk bersenang-senang :)

1 > function() {
   alert("Hi!"); 
}();

Atau

1 * function() {
   alert("Hi!"); 
}();

Atau

1 >>> function() {
   alert("Hi!"); 
}();

Atau bahkan

1 == function() {
   alert("Hi!"); 
}();

Meninggalkan ternary untuk orang lain :)

Arman McHitarian
sumber
12
0?0:function() { alert("Hi!"); }();
daniel1426
Bingo, Dan! Kami punya yang ternary;)
Arman McHitarian