Was macht das Ausrufezeichen vor der Funktion?

1242
!function () {}();
Sebastian Otto
quelle
4
@ Wykam Seine Nützlichkeit wird in dieser Antwort erklärt: stackoverflow.com/questions/5422585/…
hectorct
1
Wir nennen es Selbstausführende anonyme Funktion ---
befzz
7
@befzz Besser, dies als sofort aufgerufenen Funktionsausdruck zu bezeichnen, wie dieser Artikel später erklärt ("selbstausführend" impliziert Rekursion)
Zach Esposito

Antworten:

2118

JavaScript-Syntax 101. Hier ist eine Funktionsdeklaration :

function foo() {}

Beachten Sie, dass es kein Semikolon ist: dies ist nur eine Funktion Erklärung . Sie benötigen einen Aufruf, foo()um die Funktion tatsächlich auszuführen.

Wenn wir nun das scheinbar harmlose Ausrufezeichen hinzufügen: !function foo() {}Es verwandelt es in einen Ausdruck . Es ist jetzt ein Funktionsausdruck .

Das !allein ruft die Funktion natürlich nicht auf, aber wir können jetzt ()am Ende setzen: Das !function foo() {}()hat eine höhere Priorität als !und ruft die Funktion sofort auf.

Der Autor speichert also ein Byte pro Funktionsausdruck. Eine besser lesbare Schreibweise wäre:

(function(){})();

Zuletzt !wird der Ausdruck true zurückgegeben. Dies liegt daran, dass standardmäßig alle IIFE-Rückgaben undefined, die uns mit !undefinedwelchen zurücklassen true. Nicht besonders nützlich.

Neil
quelle
229
+1. Dies ist wirklich die beste Antwort hier und leider kaum positiv bewertet. Natürlich !gibt boolean zurück, das wissen wir alle, aber der große Punkt, den Sie ansprechen, ist, dass es auch die Funktionsdeklarationsanweisung in einen Funktionsausdruck konvertiert, sodass die Funktion sofort aufgerufen werden kann, ohne sie in Klammern zu setzen. Nicht offensichtlich und eindeutig die Absicht des Codierers.
gilly3
64
+1 Dies ist die einzige Antwort, die tatsächlich anspricht, WARUM Sie dies tun möchten, und warum man sieht, dass es mehr verwendet wird, als die Negation des Rückgabeergebnisses zu rechtfertigen scheint. Der unäre Operator! (auch ~, - und +) unterscheidet sich von einer Funktionsdeklaration und ermöglicht es den Parens am Ende (), die Funktion direkt aufzurufen. Dies wird häufig durchgeführt, um beim Schreiben von modularem Code einen lokalen Bereich / Namespace für Variablen zu erstellen.
Tom Auger
65
Ein weiterer Vorteil ist das! bewirkt, dass ein Semikolon eingefügt wird, sodass diese Version nicht fälschlicherweise mit einer Datei verknüpft werden kann, die nicht mit einem; endet. Wenn Sie das Formular () haben, wird es als Funktionsaufruf von allem betrachtet, was in der vorherigen Datei definiert wurde. Hutspitze an einen meiner Kollegen.
Jure Triglav
5
@Carnix var foo =bricht die Mehrdeutigkeit von Aussage / Ausdruck und Sie können einfach schreiben var foo = function(bar){}("baz");usw.
Neil
6
Dies erfolgt normalerweise durch Minifizierungs- / Uglifizierungsskripte, bei denen jedes einzelne Byte zählt.
Dima Slivin
367

Die Funktion:

function () {}

gibt nichts zurück (oder undefiniert).

Manchmal möchten wir eine Funktion direkt beim Erstellen aufrufen. Sie könnten versucht sein, dies zu versuchen:

function () {}()

aber es ergibt sich ein SyntaxError.

Wenn Sie den !Operator vor der Funktion verwenden, wird er als Ausdruck behandelt, sodass wir ihn aufrufen können:

!function () {}()

Dies wird auch das boolean Gegenteil von dem Rückgabewert der Funktion zurückgegeben werden , in diesem Fall true, da !undefinedist true. Wenn Sie möchten, dass der tatsächliche Rückgabewert das Ergebnis des Aufrufs ist, versuchen Sie es folgendermaßen:

(function () {})()
Michael Burr
quelle
28
Wer kann das jemals brauchen?
Andrey
13
Dies ist die einzige Antwort, die den Fall in der Frage erklärt, Bravo!
Andrey
14
Ihr zweites Codebeispiel ist kein gültiges JavaScript. Der Zweck von !ist es, die Funktionsdeklaration in einen Funktionsausdruck umzuwandeln, das ist alles.
Skilldrick
8
@Andrey Der Bootstrap Twitter verwendet dies in allen dort vorhandenen Javascript (jQuery) Plugin-Dateien. Hinzufügen dieses Kommentars für den Fall, dass andere die gleiche Frage haben.
Anmol Saraf
2
d3.js verwendet auch die !functionSyntax
Kristian
65

Es gibt einen guten Punkt für die Verwendung !für den Funktionsaufruf, der im Airbnb-JavaScript-Handbuch markiert ist

Im Allgemeinen sollten Sie diese Technik für separate Dateien (auch als Module bezeichnet) verwenden, die später verkettet werden. Die Einschränkung hierbei ist, dass Dateien von Tools verkettet werden sollen, die die neue Datei in die neue Zeile setzen (was bei den meisten Concat-Tools ohnehin üblich ist). In diesem Fall !hilft die Verwendung, Fehler zu vermeiden, wenn das zuvor verkettete Modul das nachfolgende Semikolon verpasst hat, und bietet dennoch die Flexibilität, sie ohne Bedenken in eine beliebige Reihenfolge zu bringen.

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

Funktioniert genauso wie

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

speichert aber ein Zeichen und willkürlich sieht besser aus.

Und übrigens jeder von +, -, ~, voidhaben Betreiber die gleiche Wirkung in Bezug auf die Funktion aufgerufen wird , sicher , wenn Sie etwas zu verwenden , haben von dieser Funktion zurück sie anders handeln würde.

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?

Wenn Sie jedoch IIFE-Muster für eine Datei verwenden, um einen Modulcode zu trennen, und das Concat-Tool zur Optimierung verwenden (wodurch eine Zeile zu einem Dateijob wird), wird die Konstruktion ausgeführt

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

Führt eine sichere Codeausführung durch, genau wie bei einem ersten Codebeispiel.

Dieser wird einen Fehler auslösen, da JavaScript ASI seine Arbeit nicht ausführen kann.

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

Ein Hinweis zu unären Operatoren: Sie würden ähnliche Arbeiten ausführen, aber nur für den Fall, dass sie nicht im ersten Modul verwendet werden. Sie sind also nicht so sicher, wenn Sie nicht die vollständige Kontrolle über die Verkettungsreihenfolge haben.

Das funktioniert:

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

Dies nicht:

^function abc(/*no returns*/) {}()
!function bca() {/*no returns*/}()
dmi3y
quelle
3
Tatsächlich haben diese anderen Symbole nicht den gleichen Effekt. Ja, Sie können eine Funktion wie beschrieben aufrufen, sind jedoch nicht identisch. Bedenken Sie: var foo =! Function (bar) {console.debug (bar); }("Schläger"); Egal welches Ihrer Symbole Sie vorstellen, Sie erhalten "Fledermaus" in Ihrer Konsole. Fügen Sie nun console.debug hinzu ("foo:", foo); - Sie erhalten sehr unterschiedliche Ergebnisse, je nachdem, welches Symbol Sie verwenden. ! erzwingt einen Rückgabewert, der nicht immer wünschenswert ist. Aus Gründen der Klarheit und Genauigkeit bevorzuge ich die Syntax ({}) ().
Carnix
29

Es wird zurückgegeben, ob die Anweisung als falsch ausgewertet werden kann. z.B:

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

Sie können es zweimal verwenden, um einen Wert in einen Booleschen Wert zu zwingen:

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

Um Ihre Frage direkter zu beantworten:

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

Bearbeiten: Dies hat den Nebeneffekt, dass die Funktionsdeklaration in einen Funktionsausdruck geändert wird. Der folgende Code ist beispielsweise ungültig, da er als Funktionsdeklaration interpretiert wird, bei der der erforderliche Bezeichner (oder Funktionsname ) fehlt :

function () { return false; }();  // syntax error
gilly3
quelle
6
Aus Gründen der Klarheit für die Leser , die eine Zuordnung verwenden , um mit einem sofort aufgerufen Funktion Ihres Beispielcode möchten var myVar = !function(){ return false; }()könnte weglassen der !wie var myVar = function(){ return false; }()und die Funktion wird ausgeführt , korrekt und der Rückgabewert wird unberührt.
Mark Fox
1
Um klar zu sein, können Sie es einmal verwenden, um zu Boolean zu zwingen, da es ein logischer Nicht- Operator ist. ! 0 = wahr und! 1 = falsch. Für JavaScript minification Zwecke, würden Sie ersetzen möchten , truemit !0und falsemit !1. Es werden 2 oder 3 Zeichen gespeichert.
Triynko
9

Es ist nur, um ein Datenbyte zu speichern, wenn wir Javascript-Minimierung durchführen.

Betrachten Sie die unten stehende anonyme Funktion

function (){}

Um das Obige als selbstaufrufende Funktion zu verwenden, ändern wir im Allgemeinen den obigen Code als

(function (){}())

Jetzt haben wir zwei zusätzliche Zeichen hinzugefügt, (,)abgesehen vom Hinzufügen ()am Ende der Funktion, die zum Aufrufen der Funktion erforderlich sind. Bei der Minimierung konzentrieren wir uns im Allgemeinen darauf, die Dateigröße zu reduzieren. Wir können also auch die obige Funktion als schreiben

!function (){}()

Trotzdem sind beide selbstaufrufende Funktionen und wir speichern auch ein Byte. Anstelle von 2 Zeichen haben (,)wir nur ein Zeichen verwendet!

Varatharaj
quelle
1
Dies ist hilfreich, weil Sie dies oft in minimierten js sehen
Für den Namen
5

! ist ein logischer NOT- Operator, es ist ein boolescher Operator, der etwas in das Gegenteil invertiert.

Obwohl Sie die Klammern der aufgerufenen Funktion umgehen können, indem Sie BANG (!) Vor der Funktion verwenden, wird die Rückgabe dennoch invertiert, was möglicherweise nicht Ihren Wünschen entspricht. Wie im Fall eines IEFE würde es undefiniert zurückgeben , was beim Invertieren zum booleschen Wert true wird.

Verwenden Sie stattdessen bei Bedarf die schließende Klammer und den BANG ( ! ).

// 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

Andere Operatoren, die arbeiten ...

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

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

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

Kombinierte Operatoren ...

+!(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
quelle
5

Durch das Ausrufezeichen gibt jede Funktion immer einen Booleschen Wert zurück.
Der Endwert ist die Negation des von der Funktion zurückgegebenen Werts.

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

Das Weglassen !wäre eine in den obigen Beispielen Syntax .

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

Ein besserer Weg, dies zu erreichen, wäre jedoch:

(function bool() { return true; })() // true
oozzal
quelle
Das ist falsch. !Ändert die Art und Weise, wie die Laufzeit die Funktion analysiert. Dadurch behandelt die Laufzeit die Funktion als Funktionsausdruck (und nicht als Deklaration). Auf diese Weise kann der Entwickler die Funktion sofort mithilfe der ()Syntax aufrufen . !wendet sich auch selbst (dh Negation) auf das Ergebnis des Aufrufs des Funktionsausdrucks an.
Ben Aston
3

Es ist eine andere Art, IIFE (sofort aufgerufener Funktionsausdruck) zu schreiben.

Seine andere Art zu schreiben -

(function( args ) {})()

gleich wie

!function ( args ) {}();
Kamal
quelle
Nun, es ist nicht genau das gleiche; Die 2. Form negiert das Ergebnis des Funktionsaufrufs (und wirft es dann weg, da keine Wertzuweisung erfolgt). Ich würde die explizitere (function (args) {...})()Syntax strikt bevorzugen und diese !functionForm den Minimierungs- und Verschleierungswerkzeugen überlassen .
Tobias
-1

! negiert (entgegengesetzt) ​​alles, was Sie als Ergebnis erwarten, dh wenn Sie haben

var boy = true;
undefined
boy
true
!boy
false

Wenn Sie anrufen boy, wird Ihr Ergebnis sein true, aber in dem Moment, in dem Sie das !beim Anrufen hinzufügen boy, !boywird Ihr Ergebnis sein false. Mit anderen Worten, Sie meinen NotBoy , aber diesmal ist es im Grunde ein boolesches Ergebnis, entweder trueoder false.

Das ist das gleiche, was mit dem !function () {}();Ausdruck passiert. function () {}();Wenn Sie nur ausführen, wird ein Fehler angezeigt. Wenn Sie jedoch !direkt vor Ihrem function () {}();Ausdruck hinzufügen , ist dies das Gegenteil von dem, function () {}();was Sie zurückgeben sollte true. Beispiel ist unten zu sehen:

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