Javascript-Funktion führender Knall! Syntax

204

Ich habe diese Syntax jetzt in einigen Bibliotheken gesehen und frage mich, was der Vorteil ist. (Beachten Sie, dass ich mir der Schließungen und der Funktionsweise des Codes bewusst bin. Ich mache mir nur Sorgen über die syntaktischen Unterschiede.)

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

Als Alternative zu den üblicheren

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

für selbstaufrufende anonyme Funktionen.

Ich frage mich ein paar Dinge. Was lässt das Top-Beispiel tatsächlich funktionieren? Warum ist der Knall notwendig, um diese Aussage syntaktisch korrekt zu machen? Mir wurde auch gesagt, dass das +funktioniert, und ich bin sicher, dass einige andere anstelle von!

Zweitens, was ist der Vorteil? Ich kann nur sagen, dass es einen einzelnen Charakter speichert, aber ich kann mir nicht vorstellen, dass dies ein so großer Vorteil ist, um zahlreiche Adoptierende anzulocken. Gibt es einen anderen Vorteil, den ich vermisse?

Der einzige andere Unterschied, den ich sehen kann, ist der Rückgabewert der selbstaufrufenden Funktion, aber in beiden Beispielen ist uns der Rückgabewert der Funktion nicht wirklich wichtig, da er nur zum Erstellen eines Abschlusses verwendet wird. Kann mir jemand sagen, warum man die erste Syntax verwenden könnte?

Brad
quelle
Frameworks speichern gerne so viele Zeichen wie möglich, die ein Minifier nicht optimieren kann.
alex
Der erste Vorteil, den ich habe, ist, dass Sie eine Sandbox wie (function ($) {...}) (jQuery) erstellen können.
JS Taylor
2
beide Beispiele erreichen dies. Wie bereits erwähnt, verstehe ich, was diese Funktionen tun. Ich interessiere mich mehr für die syntaktischen Unterschiede
Brad
8
Ich schreibe es der Notwendigkeit zu, nee, Anforderung, auf eine Weise süß zu sein, die raffinierter ist als die vorherige Crew. "Oh, diese Heiden in Klammern, wir haben !!"
Jared Farrish
2
Ich wusste nie davon, großartig. Ich mag das, !da es betont, dass es ausgeführt wird.
CDMckay

Antworten:

97

Idealerweise sollten Sie dies einfach so tun können:

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

Das heißt, anonyme Funktion deklarieren und ausführen. Aufgrund der Besonderheiten der JS-Grammatik funktioniert dies jedoch nicht.

Die kürzeste Form, um dies zu erreichen, ist die Verwendung eines Ausdrucks, z. B. UnaryExpression (und damit CallExpression):

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

Oder zum Spaß:

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

Oder:

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

Oder auch:

~function(){
  // do stuff
  return 0;
}( );
c-smile
quelle
3
Also dann der einzige Vorteil Knappheit?
Brad
12
Ich habe alle oben genannten Optionen zum Leistungstest hinzugefügt: jsperf.com/bang-function
Shaz
5
Ausdruckskraft würde ich sagen. Geschwindigkeit spielt in solchen Fällen keine Rolle, da sie einmal ausgeführt wird.
C-Lächeln
1
Aus Neugier bemerkte ich, dass kein Knall und Knall die schnellste Leistung erbrachte, aber irgendwo in der Entwicklung von Chrome wurde der Knall schneller als kein Knall. (Wahrscheinlich statistisch nicht signifikant, aber ...) Gibt es einen Grund dafür? Ich weiß nicht viel über Code unter der Haube, finde ihn aber ziemlich faszinierend.
jmk2142
Zwei Ihrer unären Operatoren können als binär interpretiert werden, wenn ein Semikolon fehlt. Das erste und das letzte sind die sichersten dieser Beispiele.
73

In Javascript, beginnt eine Zeile mit functionerwartet wird , eine Funktion seinem Statement und sollte aussehen

function doSomething() {
}

Eine selbstaufrufende Funktion wie

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

passt nicht , dass die Form (und wird einen Syntaxfehler an der ersten Öffnung paren verursachen , weil es keine Funktionsname ist), so werden die Brackets verwendet , um eine anonyme Funktion zu umreißen Ausdruck .

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

Aber alles, was einen Ausdruck erzeugt (im Gegensatz zu einer Funktionsanweisung), wird dies tun, daher die !. Es sagt dem Interpreter, dass dies keine Funktionsanweisung ist. Davon abgesehen bestimmt die Priorität des Operators, dass die Funktion vor der Negation aufgerufen wird.

Ich war mir dieser Konvention nicht bewusst, aber wenn sie üblich wird, kann sie zur Lesbarkeit beitragen. Was ich meine ist, dass jeder, der !functionoben in einem großen Codeblock liest, einen Selbstaufruf erwartet, so wie wir bereits konditioniert sind, um dasselbe zu erwarten, wenn wir sehen (function. Nur dass wir diese nervigen Klammern verlieren werden. Ich würde erwarten, dass dies der Grund ist, im Gegensatz zu Einsparungen bei Geschwindigkeit oder Anzahl der Charaktere.

Brainjam
quelle
Diese "Zeile, die mit der Funktion beginnt, wird erwartet ..." sieht ziemlich unscharf aus. Was ist damit:var foo = {CR/LF here} function bar() {}
c-smile
45

Neben den Dingen, die bereits gesagt wurden, ist die Syntax mit dem! ist nützlich, wenn Sie Javascript ohne Semikolons schreiben:

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

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

Das erste Beispiel gibt 'ham' wie erwartet aus, das zweite gibt jedoch einen Fehler aus, da die i = 2-Anweisung aufgrund der folgenden Klammer nicht beendet wird.

Auch in verketteten Javascript-Dateien müssen Sie sich keine Sorgen machen, wenn im vorhergehenden Code Semikolons fehlen. Also keine Notwendigkeit für das Gemeinsame; (function () {}) (); um sicherzustellen, dass Ihre eigenen nicht brechen.

Ich weiß, dass meine Antwort etwas spät ist, aber ich denke, sie wurde noch nicht erwähnt :)

Smoe
quelle
6
+1 für den Tipp und die Erinnerungen ... heutzutage schreibt niemand mehr gerne Javascript ohne Semikolons.
Pablo Grisafi
4
Twitter Bootstrap ist alles JS ohne Semikolons, und es ist ziemlich neu ... (Entschuldigung, wenn der obige Kommentar sarkastischer Natur war und ich ihn verpasst habe).
Brandwaffel
2
Das ist eigentlich nicht wahr. Betrachten Sie das folgende Beispiel :! Function () {console.log ("ham");} ()! Function () {console.log ("käse ")} (); Sie erhalten eine Fehlermeldung: "SyntaxError: Unerwartetes Token!"
HeavySixer
Ja, du hast recht. Es liegt ein Fehler vor, wenn Sie diese in dieselbe Zeile setzen. Daran habe ich nicht gedacht. Aber kein Verkettungsskript / lib, das ich bisher verwendet habe, macht das. Und wenn Sie Ihre Dateien minimieren und konzentrieren, werden Semikolons hinzugefügt. Ehrlich gesagt kann ich mir keinen Fall vorstellen, in dem Sie auf dieses Problem stoßen würden. Auf der anderen Seite ist es 2 Uhr morgens hier und ich könnte unwissend sein :)
Smoe
6

Zum einen zeigt jsPerf, dass die Verwendung von !(UnaryExpression) normalerweise schneller ist. Manchmal sind sie gleichberechtigt, aber wenn sie es nicht sind, habe ich noch nicht gesehen, wie der eine ohne Knall über die anderen triumphiert hat: http://jsperf.com/bang-function

Dies wurde auf dem neuesten Ubuntu mit dem ältesten (per say ..) Chrome, Version 8, getestet. Die Ergebnisse können also natürlich abweichen.

Edit: Wie wäre es mit etwas Verrücktem wie delete?

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

oder void?

void function() {
   alert("Hi!"); 
}();
Shaz
quelle
interessant! Ich habe ungefähr 50/50 bekommen, obwohl in Safari geschwindigkeitsmäßig, ohne Knall, sicherlich seine Position behauptet hat. Ich frage mich, ob es eine Theorie zu den möglichen Geschwindigkeitsunterschieden gibt.
Brad
@brad Muss etwas mit Safari zu tun haben. Wenn Sie sich die Tests ansehen, scheinen die meisten anderen Browser dies zu bevorzugen !. Aber ich würde auch gerne eine Theorie dazu finden :)
Shaz
3
Ich mag void, weil es explizit sagt "mir ist der Rückgabewert egal" und weil es mich an Konventionen in anderen Sprachen erinnert
code_monk
4

Wie Sie hier sehen können , verwenden Sie am besten selbst aufgerufene Methoden in Javascript:

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

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

(function(){})(); -> 69,564,370 ops/sec
Geku
quelle
1
Ich bezweifle, dass Leistung der Grund ist, die eine oder andere Syntax zu verwenden. Bei 70M Ops / Sek. Wird die Schließung ohnehin tausendmal schneller sein als der darin enthaltene Code
Eloims
3

Also mit negieren "!" und alle anderen unären Operatoren wie +, -, ~, delete, void, es wurde viel gesagt, um es zusammenzufassen:

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

Oder

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

Oder

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

Und noch ein paar Fälle mit Binäroperatoren zum Spaß :)

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

Oder

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

Oder

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

Oder auch

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

Den Ternär für jemand anderen verlassen :)

Arman McHitarian
quelle
12
0?0:function() { alert("Hi!"); }();
Daniel1426
Bingo, Dan! Wir haben die ternäre;)
Arman McHitarian