Position der Klammer für die automatische Ausführung anonymer JavaScript-Funktionen?

107

Ich habe kürzlich die aktuelle Version von json2.js mit der Version in meinem Projekt verglichen und festgestellt, dass der Funktionsausdruck anders erstellt und selbst ausgeführt wurde.

Der Code, mit dem eine anonyme Funktion in Klammern eingeschlossen und dann ausgeführt wird.

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

Jetzt wird die automatisch ausgeführte Funktion in Klammern gesetzt.

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

In der akzeptierten Antwort von Explain JavaScript's gekapselter anonymer Funktionssyntax gibt es einen Kommentar von CMS , der "beides: (function(){})();und (function(){}());gültig" lautet .

Ich habe mich gefragt, was der Unterschied ist. Nimmt der erstere Speicher auf, indem er eine globale, anonyme Funktion verlässt? Wo soll sich die Klammer befinden?

Kevin Hakanson
quelle
Verwandte: Sofortige Funktionsaufrufsyntax (in JSLint)
Bergi
1
Lesen Sie auch den Zweck dieses Konstrukts oder überprüfen Sie eine ( technische ) Erklärung (auch hier ). In dieser Frage erfahren Sie, warum die Klammern erforderlich sind .
Bergi

Antworten:

66

Sie sind praktisch gleich.

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

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

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

> function(){}()
SyntaxError: Unexpected token (
> (function(){})()
undefined
> (function(){return 'foo'})()
"foo"
> (function(){ return 'foo'}())
"foo"
meder omuraliev
quelle
8
JSLint möchte "(function () {} ());". JSLint sagt: "Verschieben Sie den Aufruf in die Parens, die die Funktion enthalten."
XP1
27
Eigentlich sind Sie nicht auf diese beiden beschränkt, Sie können fast alles verwenden, was den Compiler erkennen lässt, dass die Funktion Teil eines Ausdrucks und nicht einer Anweisung wie +function(){}()oder ist !function(){}().
Tgr
49
@ XP1: JSLint möchte viele Dinge, die spezifisch für Crockfords Stil sind, anstatt inhaltlich zu sein. Dies ist einer von ihnen.
TJ Crowder
@TJCrowder. Was würden Sie empfehlen? jQuery verwendet den ersten Stil und Crockford den zweiten.
Teej
4
@ThorpeObazee: Es ist wirklich egal, also mach was du willst. Ich würde empfehlen , gegen einige der mehr outre Einsen ( -function(){}();, !function(){}();, und im Grunde jede andere Betreiber kurz vor functionauch Arbeit, aber ich Versionen bleiben würde mit Pars). Ich sehe das erste viel mehr als das zweite, und es ist meine Präferenz; es macht auch für mich mehr Sinn, aber das ist subjektiv. FWIW: jsbin.com/ejaqow
TJ Crowder
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 definieren im zweiten Beispiel eine Funktion und rufen sie sofort auf. Sie sind ähnlich, da der Funktionsausdruck im ersten Beispiel nur die Funktionsdefinition ist.

Es gibt andere offensichtlich nützlichere Fälle zum Aufrufen von Ausdrücken, die in Funktionen aufgelöst werden:

(foo || bar)()
Triptychon
quelle
3
Zur Verdeutlichung für andere Leser (hauptsächlich, weil ich es zuerst selbst nicht verstanden habe :)) müssen foo und / oder bar bereits einer Funktion entsprechen. (zB foo = function(){alert('hi');}Wenn keine Funktion ist, wird ein Fehler ausgegeben.
Alexander Bird
3
@AlexanderBird Eine weitere Klarstellung - Es wird auch ein Fehler fooausgegeben, wenn "wahr", aber keine Funktion ist.
JLRishe
9

Über die Syntax hinaus gibt es keinen Unterschied.

In Bezug auf Ihre Bedenken hinsichtlich der zweiten Methode:

Erwägen:

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

namedfuncwird immer noch nicht im globalen Bereich sein, obwohl Sie den Namen angegeben haben. Gleiches gilt für anonyme Funktionen. Die einzige Möglichkeit, es in diesen Bereich zu bringen, besteht darin, es einer Variablen innerhalb der Parens zuzuweisen.

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

Die äußeren Parens sind unnötig:

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

Aber Sie wollten diese globale Erklärung sowieso nicht, oder?

Es läuft also darauf hinaus:

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

Und Sie können es noch weiter reduzieren: Der Name ist unnötig, da er niemals verwendet wird (es sei denn, Ihre Funktion ist rekursiv .. und selbst dann könnten Sie verwenden arguments.callee)

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

So denke ich darüber nach (möglicherweise falsch, ich habe die ECMAScript-Spezifikation noch nicht gelesen). Ich hoffe es hilft.

Cristian Sanchez
quelle
Beachten Sie, dass dies arguments.calleeseit ES5 veraltet ist (und im strengen Modus verboten ist).
Nyuszika7h
"Die äußeren Parens sind unnötig:" - Ich denke, sie verhindern Fehler, wenn Dateien verkettet werden, sonst würden Sie eine brauchen! oder so.
Jimmyt1988
-3

Der Unterschied besteht nur darin, dass Douglas Crockford den ersten Stil für IIFEs nicht mag ! (seriuosly) Wie Sie in diesem Video sehen können !!.

Der einzige Grund für das Vorhandensein der zusätzlichen Umhüllung (){in beiden Stilen} besteht darin, diesen Abschnitt des Code- Funktionsausdrucks zu erstellen , da die Funktionsdeklaration nicht sofort aufgerufen werden kann. Einige Skripte / minify-ers nur nutzen +, !, -& ~statt zu Klammern. So was:

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

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

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

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

Und all dies sind genau die gleichen wie Ihre Alternativen. Die Auswahl unter diesen Fällen liegt ganz bei Ihnen und macht keinen Unterschied. {Diejenigen mit ()produzieren 1 Byte größere Datei ;-)}

behradkhodayar
quelle