Zusammenfassung
Können Sie die Gründe für die Syntax für gekapselte anonyme Funktionen in JavaScript erläutern? Warum funktioniert das: (function(){})();
aber das nicht : function(){}();
?
Was ich weiß
In JavaScript erstellt man eine benannte Funktion wie folgt:
function twoPlusTwo(){
alert(2 + 2);
}
twoPlusTwo();
Sie können auch eine anonyme Funktion erstellen und einer Variablen zuweisen:
var twoPlusTwo = function(){
alert(2 + 2);
};
twoPlusTwo();
Sie können einen Codeblock kapseln, indem Sie eine anonyme Funktion erstellen, diese in Klammern setzen und sofort ausführen:
(function(){
alert(2 + 2);
})();
Dies ist nützlich, wenn Sie modularisierte Skripts erstellen, um zu vermeiden, dass der aktuelle oder globale Bereich mit möglicherweise widersprüchlichen Variablen überfüllt wird - wie im Fall von Greasemonkey-Skripten, jQuery-Plugins usw.
Jetzt verstehe ich, warum das funktioniert. Die Klammern schließen den Inhalt ein und zeigen nur das Ergebnis an (ich bin sicher, es gibt einen besseren Weg, dies zu beschreiben), z. B. mit (2 + 2) === 4
.
Was ich nicht verstehe
Aber ich verstehe nicht, warum das nicht genauso gut funktioniert:
function(){
alert(2 + 2);
}();
Kannst du mir das erklären?
quelle
Antworten:
Es funktioniert nicht, weil es als analysiert
FunctionDeclaration
wird und die Namenskennung von Funktionsdeklarationen obligatorisch ist .Wenn Sie es mit Klammern umgeben, wird es als a ausgewertet
FunctionExpression
, und Funktionsausdrücke können benannt werden oder nicht.Die Grammatik von a
FunctionDeclaration
sieht so aus:Und
FunctionExpression
s:Wie Sie sehen können, ist das Token
Identifier
(Identifier opt )FunctionExpression
optional, daher können wir einen Funktionsausdruck ohne definierten Namen haben:Oder benannter Funktionsausdruck:
Die Klammern (formal als Gruppierungsoperator bezeichnet ) können nur Ausdrücke umgeben, und ein Funktionsausdruck wird ausgewertet.
Die beiden Grammatikproduktionen können mehrdeutig sein und genau gleich aussehen, zum Beispiel:
Der Parser weiß, ob es sich um ein
FunctionDeclaration
oder ein handeltFunctionExpression
, je nachdem, in welchem Kontext es angezeigt wird.Im obigen Beispiel ist der zweite ein Ausdruck, da der Komma-Operator auch nur Ausdrücke verarbeiten kann.
Andererseits
FunctionDeclaration
könnte s tatsächlich nur im sogenannten "Program
" Code erscheinen, dh Code außerhalb des globalen Bereichs und innerhalbFunctionBody
anderer Funktionen.Funktionen innerhalb von Blöcken sollten vermieden werden, da sie zu einem unvorhersehbaren Verhalten führen können, z.
Der obige Code sollte tatsächlich a erzeugen
SyntaxError
, da aBlock
nur Anweisungen enthalten kann (und die ECMAScript-Spezifikation keine Funktionsanweisung definiert), die meisten Implementierungen jedoch tolerant sind und einfach die zweite Funktion übernehmen, die alarmiert'false!'
.Die Mozilla-Implementierungen - Nashorn, SpiderMonkey - haben ein anderes Verhalten. Ihre Grammatik enthält eine nicht standardmäßige Funktionsanweisung, was bedeutet, dass die Funktion bei bewertet wird Laufzeit und nicht zur Analysezeit wird, wie dies bei
FunctionDeclaration
s der . In diesen Implementierungen wird die erste Funktion definiert.Funktionen können auf verschiedene Arten deklariert werden. Vergleichen Sie Folgendes :
1- Eine Funktion, die mit dem der Variablen multiplizierten Funktionskonstruktor multipliziert wurde :
2- Eine Funktionsdeklaration einer Funktion namens multiplizieren :
3- Ein der Variablen multiplizierter Funktionsausdruck multiplizieren :
4- Ein benannter Funktionsausdruck func_name , der der Variablen multiplizieren zugewiesen ist :
quelle
Obwohl dies eine alte Frage und Antwort ist, wird ein Thema behandelt, das bis heute viele Entwickler für eine Schleife wirft. Ich kann die Anzahl der von mir befragten JavaScript-Entwicklerkandidaten nicht zählen, die mir den Unterschied zwischen einer Funktionsdeklaration und einem Funktionsausdruck nicht sagen konnten und die keine Ahnung hatten, was ein sofort aufgerufener Funktionsausdruck ist.
Ich möchte jedoch eine sehr wichtige Sache erwähnen, nämlich, dass Premasagars Code-Snippet nicht funktionieren würde, selbst wenn er ihm eine Namenskennung gegeben hätte.
Der Grund, warum dies nicht funktionieren würde, ist, dass die JavaScript-Engine dies als Funktionsdeklaration interpretiert, gefolgt von einem völlig unabhängigen Gruppierungsoperator, der keinen Ausdruck enthält, und Gruppierungsoperatoren müssen einen Ausdruck enthalten. Laut JavaScript entspricht der obige Codeausschnitt dem folgenden.
Eine andere Sache, auf die ich hinweisen möchte, die für manche Menschen von Nutzen sein kann, ist, dass jede Namenskennung, die Sie für einen Funktionsausdruck angeben, im Kontext des Codes so gut wie nutzlos ist, außer innerhalb der Funktionsdefinition selbst.
Natürlich ist die Verwendung von Namenskennungen mit Ihren Funktionsdefinitionen immer hilfreich, wenn es um das Debuggen von Code geht, aber das ist etwas ganz anderes ... :-)
quelle
Gute Antworten wurden bereits veröffentlicht. Ich möchte jedoch darauf hinweisen, dass Funktionsdeklarationen einen leeren Abschlussdatensatz zurückgeben:
Diese Tatsache ist nicht leicht zu beobachten, da die meisten Methoden zum Abrufen des zurückgegebenen Werts die Funktionsdeklaration in einen Funktionsausdruck konvertieren. Allerdings
eval
zeigt es:Das Aufrufen eines leeren Abschlussdatensatzes macht keinen Sinn. Deshalb
function f(){}()
kann ich nicht arbeiten. Tatsächlich versucht die JS-Engine nicht einmal, sie aufzurufen. Die Klammern werden als Teil einer anderen Anweisung betrachtet.Wenn Sie die Funktion jedoch in Klammern setzen, wird sie zu einem Funktionsausdruck:
Funktionsausdrücke geben ein Funktionsobjekt zurück. Und deshalb können Sie es nennen :
(function f(){})()
.quelle
In Javascript wird dies als sofort aufgerufener Funktionsausdruck (IIFE) bezeichnet .
Um es zu einem Funktionsausdruck zu machen, müssen Sie:
füge es mit () bei
Stellen Sie einen leeren Operator davor
Weisen Sie es einer Variablen zu.
Andernfalls wird es als Funktionsdefinition behandelt, und Sie können es dann nicht gleichzeitig auf folgende Weise aufrufen / aufrufen:
Das obige gibt Ihnen Fehler. Weil Sie einen Funktionsausdruck nur sofort aufrufen können.
Dies kann auf verschiedene Arten erreicht werden: Weg 1:
Weg 2:
Weg 3:
Weg 4:
Alle oben genannten Elemente rufen sofort den Funktionsausdruck auf.
quelle
Ich habe nur eine weitere kleine Bemerkung. Ihr Code funktioniert mit einer kleinen Änderung:
Ich verwende die obige Syntax anstelle der weiter verbreiteten Version:
weil ich es nicht geschafft habe, dass der Einzug für Javascript-Dateien in vim richtig funktioniert. Es scheint, dass vim die geschweiften Klammern in offenen Klammern nicht mag.
quelle
function
Schlüsselwort beginnt, als Funktionsdeklaration()
interpretiert. In diesem Fall wird das Trailing als Gruppierungsoperator interpretiert , der gemäß den JavaScript-Syntaxregeln nur einen JavaScript-Ausdruck enthalten kann und muss .()
die im Gruppierungsoperator enthalten ist (die von Douglas Crockford dringend empfohlene): Es ist üblich, IIFEs zu verwenden, ohne sie einer Variablen zuzuweisen, und es ist leicht zu vergessen, diese umschließenden Klammern einzuschließen, wenn Sie sie nicht konsistent verwenden.Vielleicht wäre die kürzere Antwort das
ist ein Funktionsliteral , das eine (anonyme) Funktion definiert. Ein zusätzliches () -Paar, das als Ausdruck interpretiert wird, wird auf oberster Ebene nicht erwartet, sondern nur Literale.
befindet sich in einer Ausdrucksanweisung , die eine anonyme Funktion aufruft .
quelle
Oben ist eine gültige Syntax angegeben, da alles, was in Klammern übergeben wird, als Funktionsausdruck betrachtet wird.
Oben ist keine gültige Syntax. Da der Java-Skriptsyntax-Parser nach dem Funktionsschlüsselwort nach dem Funktionsnamen sucht, da er nichts findet, wird ein Fehler ausgegeben.
quelle
Sie können es auch wie folgt verwenden:
oder
!
- negation op konvertiert die fn-Definition in einen fn-Ausdruck, daher können Sie sie sofort mit aufrufen()
. Gleich wie mit0,fn def
odervoid fn def
quelle
Sie können mit Parameter-Argumenten wie verwendet werden
würde als 7 ergeben
quelle
Diese zusätzliche Klammer erstellt zusätzliche anonyme Funktionen zwischen dem globalen Namespace und der anonymen Funktion, die den Code enthält. Und in Javascript-Funktionen, die in anderen Funktionen deklariert sind, kann nur auf den Namespace der übergeordneten Funktion zugegriffen werden, die sie enthält. Da zwischen dem globalen Bereich und dem tatsächlichen Code-Scoping ein zusätzliches Objekt (anonyme Funktion) besteht, wird es nicht beibehalten.
quelle