Apa yang dilakukan tanda seru sebelum fungsi?

1242
!function () {}();
Sebastian Otto
sumber
4
@Dykam Kegunaannya dijelaskan dalam jawaban ini: stackoverflow.com/questions/5422585/…
hectorct
1
Kami menyebutnya fungsi anonim yang dijalankan sendiri ---
befzz
7
@ befzz Lebih baik menyebut ini sebagai Ekspresi Fungsi yang Segera Diminta, seperti yang dijelaskan artikel itu nanti ("mengeksekusi sendiri" menyiratkan rekursi)
Zach Esposito

Jawaban:

2118

Sintaks JavaScript 101. Ini adalah deklarasi fungsi :

function foo() {}

Perhatikan bahwa tidak ada titik koma: ini hanya deklarasi fungsi . Anda perlu doa foo(),, untuk benar-benar menjalankan fungsinya.

Sekarang, ketika kita menambahkan tanda seru yang tampaknya tidak berbahaya: !function foo() {}itu mengubahnya menjadi ekspresi . Sekarang merupakan ekspresi fungsi .

Itu !saja tidak memanggil fungsi, tentu saja, tetapi kita sekarang dapat menempatkan ()di akhir: !function foo() {}()yang memiliki prioritas lebih tinggi daripada !dan langsung memanggil fungsi.

Jadi apa yang penulis lakukan adalah menyimpan byte per fungsi ekspresi; cara penulisan yang lebih mudah dibaca adalah:

(function(){})();

Terakhir, !jadikan ungkapan itu benar. Hal ini karena secara default semua Iife kembali undefined, yang meninggalkan kita dengan !undefinedyang true. Tidak terlalu bermanfaat.

Neil
sumber
229
+1. Ini benar-benar jawaban terbaik di sini, dan sayangnya, hampir tidak terangkat. Jelas, !mengembalikan boolean, kita semua tahu itu, tetapi poin bagus yang Anda buat adalah bahwa ia juga mengubah pernyataan pernyataan fungsi ke ekspresi fungsi sehingga fungsi tersebut dapat langsung dipanggil tanpa membungkusnya dalam tanda kurung. Tidak jelas, dan jelas maksud si pembuat kode.
gilly3
64
+1 Ini adalah satu-satunya jawaban yang benar-benar membahas MENGAPA Anda ingin melakukan ini, dan mengapa orang melihatnya lebih banyak digunakan daripada negasi hasil pengembalian tampaknya perlu. Operator unary! (juga ~, - dan +) dipisahkan dari deklarasi fungsi, dan memungkinkan parens di akhir () untuk memanggil fungsi di tempat. Ini sering dilakukan untuk membuat lingkup lokal / namespace untuk variabel saat menulis kode modular.
Tom Auger
65
Manfaat lain adalah itu! menyebabkan penyisipan semi-kolon, jadi tidak mungkin untuk versi ini disalahgunakan secara keliru dengan file yang tidak diakhiri dengan; Jika Anda memiliki formulir (), itu akan menganggapnya sebagai panggilan fungsi apa pun yang didefinisikan dalam file sebelumnya. Ujung topi untuk rekan kerja saya.
Jure Triglav
5
@Carnix var foo =memecahkan pernyataan / ekspresi ambiguitas dan Anda cukup menulis var foo = function(bar){}("baz");dll.
Neil
6
Ini biasanya dilakukan oleh skrip minifikasi / uglifikasi, di mana setiap byte dihitung.
Dima Slivin
367

Fungsi:

function () {}

tidak menghasilkan apa-apa (atau tidak terdefinisi).

Terkadang kita ingin memanggil fungsi dengan benar saat kita membuatnya. Anda mungkin tergoda untuk mencoba ini:

function () {}()

tetapi menghasilkan SyntaxError.

Menggunakan !operator sebelum fungsi menyebabkannya diperlakukan sebagai ekspresi, sehingga kita dapat menyebutnya:

!function () {}()

Ini juga akan kembali kebalikan boolean dari nilai kembali fungsi, dalam hal ini true, karena !undefinedini true. Jika Anda ingin nilai pengembalian yang sebenarnya adalah hasil dari panggilan, maka coba lakukan dengan cara ini:

(function () {})()
Michael Burr
sumber
28
siapa yang bisa membutuhkan ini?
Andrey
13
ini adalah satu - satunya jawaban yang menjelaskan kasus dalam pertanyaan, bravo!
Andrey
14
Sampel kode kedua Anda bukan JavaScript yang valid. Tujuan dari !adalah untuk mengubah deklarasi fungsi menjadi ekspresi fungsi, itu saja.
Skilldrick
8
@Andrey Twitter bootstrap menggunakan ini di semua file plugin javascript (jQuery). Menambahkan komentar ini untuk berjaga-jaga kalau-kalau orang lain juga memiliki pertanyaan yang sama.
Anmol Saraf
2
d3.js juga menggunakan !functionsintaks
Kristian
65

Ada poin yang baik untuk digunakan !untuk pemanggilan fungsi yang ditandai pada panduan JavaScript airbnb

Secara umum ide untuk menggunakan teknik ini pada file terpisah (modul alias) yang kemudian digabungkan. Peringatan di sini adalah bahwa file seharusnya disatukan oleh alat yang meletakkan file baru di baris baru (yang merupakan perilaku umum untuk sebagian besar alat concat). Dalam hal itu, menggunakan !akan membantu untuk menghindari kesalahan jika modul yang sebelumnya telah dikenali ketinggalan tanda titik koma, dan itu akan memberikan fleksibilitas untuk menempatkannya dalam urutan apa pun tanpa khawatir.

!function abc(){}();
!function bca(){}();

Akan bekerja sama dengan

!function abc(){}();
(function bca(){})();

tetapi menyimpan satu karakter dan sewenang-wenang terlihat lebih baik.

Dan omong-omong apapun +, -, ~, voidoperator memiliki efek yang sama, dalam hal memohon fungsi, pasti jika Anda harus menggunakan sesuatu untuk kembali dari fungsi mereka akan bertindak berbeda.

abcval = !function abc(){return true;}() // abcval equals false
bcaval = +function bca(){return true;}() // bcaval equals 1
zyxval = -function zyx(){return true;}() // zyxval equals -1
xyzval = ~function xyz(){return true;}() // your guess?

tetapi jika Anda menggunakan pola IIFE untuk satu file satu pemisahan kode modul dan menggunakan alat concat untuk optimasi (yang membuat satu baris satu pekerjaan file), maka konstruksi

!function abc(/*no returns*/) {}()
+function bca() {/*no returns*/}()

Akan melakukan eksekusi kode aman, sama dengan contoh kode pertama.

Yang ini akan melempar kesalahan karena JavaScript ASI tidak akan dapat melakukan tugasnya.

!function abc(/*no returns*/) {}()
(function bca() {/*no returns*/})()

Satu catatan tentang operator unary, mereka akan melakukan pekerjaan yang sama, tetapi hanya dalam kasus, mereka tidak menggunakan modul pertama. Jadi mereka tidak begitu aman jika Anda tidak memiliki kendali penuh atas urutan penyatuan.

Ini bekerja:

!function abc(/*no returns*/) {}()
^function bca() {/*no returns*/}()

Ini bukan:

^function abc(/*no returns*/) {}()
!function bca() {/*no returns*/}()
dmi3y
sumber
3
Sebenarnya, simbol-simbol lainnya tidak memiliki efek yang sama. Ya, mereka memungkinkan Anda untuk memanggil fungsi seperti yang dijelaskan, tetapi mereka tidak identik. Pertimbangkan: var foo =! Function (bar) {console.debug (bar); }("kelelawar"); Apa pun simbol yang Anda letakkan di depan, Anda mendapatkan "kelelawar" di konsol Anda. Sekarang, tambahkan console.debug ("foo:", foo); - Anda mendapatkan hasil yang sangat berbeda berdasarkan simbol apa yang Anda gunakan. ! memaksa nilai kembali yang tidak selalu diinginkan. Saya lebih suka sintaks ({}) () untuk kejelasan dan akurasi.
Carnix
29

Ini mengembalikan apakah pernyataan dapat mengevaluasi ke false. misalnya:

!false      // true
!true       // false
!isValid()  // is not valid

Anda dapat menggunakannya dua kali untuk memaksa nilai ke boolean:

!!1    // true
!!0    // false

Jadi, untuk lebih langsung menjawab pertanyaan Anda:

var myVar = !function(){ return false; }();  // myVar contains true

Sunting: Ini memiliki efek samping dari mengubah deklarasi fungsi ke ekspresi fungsi. Misalnya kode berikut ini tidak valid karena ditafsirkan sebagai deklarasi fungsi yang tidak memiliki pengidentifikasi yang diperlukan (atau nama fungsi ):

function () { return false; }();  // syntax error
gilly3
sumber
6
Demi kejelasan bagi pembaca yang mungkin ingin menggunakan tugas dengan fungsi segera dipanggil kode contoh Anda var myVar = !function(){ return false; }()bisa menghilangkan !sejenisnya var myVar = function(){ return false; }()dan fungsi akan mengeksekusi dengan benar dan nilai kembali akan tersentuh.
Mark Fox
1
Untuk lebih jelasnya, Anda dapat menggunakannya sekali untuk memaksa ke Boolean, karena itu logis bukan operator. ! 0 = benar, dan! 1 = salah. Untuk keperluan minimalisasi JavaScript, Anda ingin mengganti truedengan !0dan falsedengan !1. Ini menghemat 2 atau 3 karakter.
Triynko
9

Hanya untuk menyimpan satu byte data saat kita melakukan minavascript.

pertimbangkan fungsi anonim di bawah ini

function (){}

Untuk menjadikan di atas sebagai fungsi pemanggilan mandiri, kami biasanya akan mengubah kode di atas sebagai

(function (){}())

Sekarang kami menambahkan dua karakter tambahan (,)selain menambahkan ()di akhir fungsi yang diperlukan untuk memanggil fungsi. Dalam proses minifikasi biasanya kita fokus untuk mengurangi ukuran file. Jadi kita juga bisa menulis fungsi di atas sebagai

!function (){}()

Masih keduanya adalah fungsi yang dapat dipanggil sendiri dan kami menyimpan byte juga. Alih-alih 2 karakter, (,)kami hanya menggunakan satu karakter!

Varatharaj
sumber
1
Ini membantu karena sering kali Anda akan melihat ini dalam js minified
For the Name
5

! adalah operator TIDAK logis , itu adalah operator boolean yang akan membalikkan sesuatu yang berlawanan.

Meskipun Anda dapat mem-bypass kurung dari fungsi yang dipanggil dengan menggunakan BANG (!) Sebelum fungsi, itu masih akan membalikkan pengembalian, yang mungkin bukan apa yang Anda inginkan. Seperti dalam kasus IEFE, itu akan kembali tidak terdefinisi , yang ketika dibalik menjadi boolean benar.

Alih-alih, gunakan tanda kurung penutup dan BANG ( ! ) Jika perlu.

// I'm going to leave the closing () in all examples as invoking the function with just ! and () takes away from what's happening.

(function(){ return false; }());
=> false

!(function(){ return false; }());
=> true

!!(function(){ return false; }());
=> false

!!!(function(){ return false; }());
=> true

Operator lain yang bekerja ...

+(function(){ return false; }());
=> 0

-(function(){ return false; }());
=> -0

~(function(){ return false; }());
=> -1

Operator Gabungan ...

+!(function(){ return false; }());
=> 1

-!(function(){ return false; }());
=> -1

!+(function(){ return false; }());
=> true

!-(function(){ return false; }());
=> true

~!(function(){ return false; }());
=> -2

~!!(function(){ return false; }());
=> -1

+~(function(){ return false; }());
+> -1
SoEzPz
sumber
5

Tanda seru membuat fungsi apa pun selalu mengembalikan boolean.
Nilai akhir adalah negasi dari nilai yang dikembalikan oleh fungsi.

!function bool() { return false; }() // true
!function bool() { return true; }() // false

Menghilangkan !contoh-contoh di atas akan menjadi Sintaksis .

function bool() { return true; }() // SyntaxError

Namun, cara yang lebih baik untuk mencapai ini adalah:

(function bool() { return true; })() // true
oozzal
sumber
Ini salah. !mengubah cara runtime mem-parsing fungsi. Itu membuat runtime memperlakukan fungsi sebagai ekspresi fungsi (dan bukan deklarasi). Ini melakukan ini untuk memungkinkan pengembang untuk segera memanggil fungsi menggunakan ()sintaks. !juga akan berlaku sendiri (yaitu negasi) pada hasil memohon ekspresi fungsi.
Ben Aston
3

Ini cara lain untuk menulis IIFE (ekspresi fungsi yang segera dipanggil).

Cara penulisan lainnya -

(function( args ) {})()

sama dengan

!function ( args ) {}();
kamal
sumber
Yah, itu tidak persis sama; formulir ke-2 meniadakan hasil pemanggilan fungsi (dan kemudian membuangnya, karena tidak ada penetapan nilai). Saya lebih suka (function (args) {...})()sintaksis yang lebih eksplisit dan meninggalkan !functionformulir itu ke alat minifikasi dan kebingungan.
Tobias
-1

! akan meniadakan (berlawanan) apapun yang Anda harapkan sebagai hasilnya, yaitu jika Anda miliki

var boy = true;
undefined
boy
true
!boy
false

ketika Anda menelepon boy, hasilnya Anda akan true, tetapi saat Anda menambahkan !saat menelepon boy, yaitu !boy, hasil Anda akan false. Yang dengan kata lain maksud Anda NotBoy , tapi kali ini pada dasarnya merupakan hasil boolean, baik trueatau false.

Itu adalah hal yang sama yang terjadi pada !function () {}();ekspresi, menjalankan hanya function () {}();akan menandai Anda kesalahan, tetapi menambahkan !tepat di depan function () {}();ekspresi Anda , membuatnya menjadi kebalikan dari function () {}();yang seharusnya mengembalikan Anda true. Contohnya bisa dilihat di bawah ini:

function () {}();
SyntaxError: function statement requires a name
!function () {}();
true
antzshrek
sumber