Posizione delle parentesi per l'esecuzione automatica delle funzioni JavaScript anonime?


107

Recentemente stavo confrontando la versione corrente di json2.js con la versione che avevo nel mio progetto e ho notato una differenza nel modo in cui l'espressione della funzione è stata creata ed eseguita automaticamente.

Il codice utilizzato per racchiudere una funzione anonima tra parentesi e quindi eseguirla,

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

ma ora racchiude tra parentesi la funzione eseguita automaticamente.

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

C'è un commento di CMS nella risposta accettata della sintassi della funzione anonima incapsulata di Explain JavaScript che "sia: (function(){})();che (function(){}());sono validi".

Mi chiedevo qual è la differenza? Il primo occupa la memoria lasciando una funzione globale e anonima? Dove dovrebbe essere posizionata la parentesi?



Correlati: sintassi di chiamata di funzione immediata (in JSLint)
Bergi

1
Leggi anche lo scopo di questo costrutto o controlla una spiegazione ( tecnica ) (anche qui ). Per sapere perché le parentesi sono necessarie, vedere questa domanda .
Bergi

Risposte:


66

Sono praticamente la stessa cosa.

Il primo racchiude tra parentesi una funzione per renderla un'espressione valida e la invoca. Il risultato dell'espressione non è definito.

Il secondo esegue la funzione e le parentesi attorno alla chiamata automatica ne fanno un'espressione valida. Inoltre restituisce undefined.

Non credo che ci sia un modo "giusto" di farlo, poiché il risultato dell'espressione è lo stesso.

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

8
JSLint vuole "(function () {} ());". JSLint dice: "Sposta l'invocazione nelle parentesi che contengono la funzione".
XP1

27
In realtà non sei limitato a questi due, puoi usare praticamente qualsiasi cosa che faccia capire al compilatore che la funzione è parte di un'espressione e non di un'istruzione, come +function(){}()o !function(){}().
Tgr

49
@ XP1: JSLint vuole molte cose che sono specifiche dello stile di Crockford piuttosto che essere sostanziali. Questo è uno di loro.
TJ Crowder

@TJCrowder. Cosa raccomanderesti? jQuery usa il primo stile e Crockford usa il secondo.
Teej

4
@ThorpeObazee: Non importa davvero, quindi fai quello che preferisci. Consiglierei contro alcuni di quelli più outre ( -function(){}();, !function(){}();e fondamentalmente anche qualsiasi altro operatore appena prima functionfunziona, ma mi atterrei alle versioni che utilizzano parentesi). Vedo il primo molto di più rispetto al secondo, ed è una mia preferenza; ha più senso anche per me, ma è soggettivo. FWIW: jsbin.com/ejaqow
TJ Crowder

13

In quel caso non importa. Si richiama un'espressione che si risolve in una funzione nella prima definizione e si definisce e si richiama immediatamente una funzione nel secondo esempio. Sono simili perché l'espressione della funzione nel primo esempio è solo la definizione della funzione.

Ci sono altri casi più ovviamente utili per invocare espressioni che si risolvono in funzioni:

(foo || bar)()

3
Per chiarimenti ad altri lettori (principalmente perché all'inizio non l'ho capito io :)), foo e / o bar devono già eguagliare qualche funzione. (es foo = function(){alert('hi');}. Se nessuna delle due è una funzione, viene generato un errore.
Alexander Bird

3
@AlexanderBird Un ulteriore chiarimento - Verrà anche generato un errore se fooè "veritiero" ma non è una funzione.
JLRishe

9

Non c'è alcuna differenza oltre la sintassi.

Per quanto riguarda le tue preoccupazioni sul secondo metodo per farlo:

Tener conto di:

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

namedfuncnon sarà ancora nell'ambito globale anche se hai fornito il nome. Lo stesso vale per le funzioni anonime. L'unico modo per ottenerlo in tale ambito sarebbe assegnarlo a una variabile all'interno delle parentesi.

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

Le parentesi esterne non sono necessarie:

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

Ma non volevi comunque quella dichiarazione globale, vero?

Quindi si riduce a:

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

E puoi ridurlo ancora di più: il nome non è necessario poiché non verrà mai utilizzato (a meno che la tua funzione non sia ricorsiva .. e anche allora potresti usare arguments.callee)

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

Questo è il modo in cui la penso (potrebbe non essere corretto, non ho ancora letto la specifica ECMAScript). Spero che sia d'aiuto.


Nota che arguments.calleeè deprecato da ES5 (e proibito in modalità rigorosa).
nyuszika7h

"Le parentesi esterne non sono necessarie:" - Penso che impediscano errori quando i file vengono concatenati, altrimenti avresti bisogno di un! o qualcosa.
Jimmyt1988

-3

La differenza esiste solo perché a Douglas Crockford non piace il primo stile per gli IIFE ! (seriamente) Come puoi vedere in questo video !! .

L'unico motivo per l'esistenza del wrapping extra (){in entrambi gli stili} è aiutare a rendere quella sezione del codice Function Expression , perché la Function Declaration non può essere chiamata immediatamente. Alcuni script / minify-ERS solo utilizzo +, !, -e ~invece di troppo parentesi. Come questo:

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

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

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

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

E tutti questi sono esattamente gli stessi delle tue alternative. La scelta tra questi casi è completamente tua e non fa differenza. {Quelli che ()producono un file più grande di 1 byte ;-)}

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.