2010-08-02 12 views
96

Ich habe kürzlich die aktuelle Version von json2.js mit der Version verglichen, die ich in meinem Projekt hatte und bemerkte einen Unterschied in der Art, wie der Funktionsausdruck erstellt und selbst ausgeführt wurde.Position der Klammern für die automatische Ausführung anonymer JavaScript-Funktionen?

Der Code verwendet eine anonyme Funktion in Klammern zu wickeln und dann,

(function() { 
    // code here 
})(); 

ausführen, aber jetzt wickelt es die Auto-ausgeführte Funktion in Klammern.

(function() { 
    // code here 
}()); 

Es ist ein Kommentar von CMS in der akzeptierte Antwort von Explain JavaScript’s encapsulated anonymous function syntax, dass „beide. (function(){})(); und (function(){}()); gültig sind“

Ich habe mich gefragt, was der Unterschied ist? Nimmt das erstere Speicher auf, indem es um eine globale, anonyme Funktion herumgeht? Wo sollte sich die Klammer befinden?

+1

Siehe auch [Differenz zwischen (function() {})(); und function() {}();] (http://stackoverflow.com/q/423228/1048572) und [Gibt es einen Unterschied zwischen (function() {...}()); und (function() {...})();?] (http://stackoverflow.com/q/3783007/1048572) – Bergi

+0

Related: [Sofortige Funktionsaufrufsyntax] (http://stackoverflow.com/q/939386/1048572) (in JSLint) – Bergi

+1

Lesen Sie auch über den [Zweck dieses Konstrukts] (http://stackoverflow.com/q/592396/1048572), oder überprüfen Sie eine ([technische] (http://stackoverflow.com/ q/4212149/1048572)) [Erklärung] (http://stackoverflow.com/q/8228281/1048572) (auch [hier] (http://stackoverflow.com/a/441498/1048572)). Für warum die Klammern notwendig sind, siehe [diese Frage] (http://stackoverflow.com/q/1634268/1048572). – Bergi

Antwort

59

Sie sind praktisch gleich.

Die erste umschließt Klammern um eine Funktion, um sie zu einem gültigen Ausdruck zu machen, und ruft sie auf. Das Ergebnis des Ausdrucks ist nicht definiert.

Die zweite führt die Funktion und die Klammern um den automatischen Aufruf machen es zu einem gültigen Ausdruck. Es wird auch zu undefiniert ausgewertet.

Ich glaube nicht, dass es einen "richtigen" Weg gibt, es zu tun, da das Ergebnis des Ausdrucks das gleiche ist.

> function(){}() 
SyntaxError: Unexpected token (
> (function(){})() 
undefined 
> (function(){return 'foo'})() 
"foo" 
> (function(){ return 'foo'}()) 
"foo" 
+8

JSLint möchte "(function() {}());". JSLint sagt: "Verschiebe den Aufruf in die Parens, die die Funktion enthalten." – XP1

+26

Eigentlich sind Sie nicht auf diese beiden beschränkt, Sie können fast alles verwenden, was den Compiler dazu bringt, zu erkennen, dass die Funktion Teil eines Ausdrucks ist und keine Anweisung wie '+ function() {}()' oder '! Function()) {}() '. – Tgr

+45

@ XP1: JSLint will viele Dinge, die spezifisch für Crockfords * Stil sind, anstatt substanziell zu sein. Dies ist einer von ihnen. –

13

In diesem Fall spielt es keine Rolle. Sie rufen einen Ausdruck auf, der in der ersten Definition in eine Funktion aufgelöst wird und im zweiten Beispiel eine Funktion definiert und sofort aufruft. Sie sind ähnlich, weil der Funktionsausdruck im ersten Beispiel nur die Funktionsdefinition ist.

Es gibt andere offensichtlich nützliche Fälle für Ausdrücke Aufruf, die Funktionen beheben:

(foo || bar)() 
+3

Zur Verdeutlichung für andere Leser (vor allem, weil ich es zuerst selbst nicht verstanden habe :)), müssen foo und/oder bar schon gleich einige sein Funktion. (zB 'foo = function() {alert ('hi');}'. Wenn es keine Funktion gibt, wird ein Fehler ausgelöst. –

+2

@AlexanderBird Eine weitere Klarstellung - Es wird auch ein Fehler ausgegeben, wenn 'foo'" truthy "ist "Aber keine Funktion. – JLRishe

7

Es gibt keinen Unterschied über die Syntax.

In Bezug auf Ihre Bedenken über die zweite Methode, es zu tun:

Bedenken Sie:

(function namedfunc() { ... }())

namedfunc wird im globalen Bereich noch nicht einmal sein, obwohl Sie den Namen zur Verfügung gestellt. Das gleiche gilt für anonyme Funktionen. Der einzige Weg, um es in diesem Bereich zu bekommen, wäre, es einer Variablen innerhalb des Parens zuzuordnen.

((namedfunc = function namedfunc() { ... })()) 

Die äußeren Pars sind nicht erforderlich:

(namedfunc = function namedfunc() { ... })() 

Aber Sie nicht, dass die globale Erklärung sowieso wollte, hast du?

Also es läuft darauf hinaus:

(function namedfunc() { ... })() 

Und Sie können es noch weiter reduzieren: der Name ist nicht erforderlich, da es nie (verwendet werden, wenn Ihre Funktion rekursiv ist .. und selbst dann könnten Sie arguments.callee)

(function() { ... })() 

das ist die Art, wie ich darüber nachdenke (möglicherweise falsch, ich habe nicht die ECMAScript-Spezifikation noch) nicht. Ich hoffe es hilft.

-3

Der Unterschied existiert nur, weil Douglas Crockford die erste Art für IIFEs nicht mag! (seriös) As you can see in this video!!.

Der einzige Grund für die Existenz der zusätzlichen Umhüllung () {in beiden Stilen} ist, dass die Code-Abschnitt Funktion Expression sofort aufgerufen werden kann, nicht, weil Funktion Deklaration zu helfen. Einige Scripts/Minifyers verwenden einfach +, , - & ~ anstelle von Klammern. Wie folgt:

+function() { 
    var foo = 'bar'; 
}(); 

!function() { 
    var foo = 'bar'; 
}(); 

-function() { 
    var foo = 'bar'; 
}(); 

~function() { 
    var foo = 'bar'; 
}(); 

Und alle diese sind genau das gleiche wie Ihre Alternativen. Die Wahl zwischen diesen Fällen ist komplett auf Ihre eigenen & macht keinen Unterschied. {Die mit () produzieren 1 Byte größere Datei ;-)}

Verwandte Themen