2010-08-02 17 views
96

Recentemente ho confrontato 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 autonomamente.Posizione della parentesi per l'esecuzione automatica di funzioni JavaScript anonime?

Il codice utilizzato per avvolgere una funzione anonima tra parentesi e poi eseguirlo,

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

ma ora avvolge la funzione di auto-eseguito in parentesi.

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

C'è un commento di CMS nella risposta accettato di Explain JavaScript’s encapsulated anonymous function syntax che “entrambe le cose:. (function(){})(); e (function(){}()); sono validi”

mi chiedevo qual è la differenza? Il primo occupa la memoria abbandonando una funzione globale anonima? Dove dovrebbe essere localizzata la parentesi?

+1

Vedere anche [Differenza tra (function() {})(); e function() {}();] (http://stackoverflow.com/q/423228/1048572) e [Esiste una differenza tra (function() {...}()); e (function() {...})();?] (http://stackoverflow.com/q/3783007/1048572) – Bergi

+0

correlati: [Sintassi di chiamata di funzione immediata] (http://stackoverflow.com/q/939386/1048572) (in JSLint) – Bergi

+1

Leggi anche [lo scopo di questo costrutto] (http://stackoverflow.com/q/592396/1048572), oppure controlla un ([tecnico] (http://stackoverflow.com/ q/4212149/1048572)) [spiegazione] (http://stackoverflow.com/q/8228281/1048572) (anche [qui] (http://stackoverflow.com/a/441498/1048572)). Perchè le parentesi sono necessarie, vedi [questa domanda] (http://stackoverflow.com/q/1634268/1048572). – Bergi

risposta

59

Sono praticamente uguali.

Il primo avvolge le parentesi attorno a una funzione per trasformarla in un'espressione valida e invocarla. Il risultato dell'espressione è indefinito.

Il secondo esegue la funzione e le parentesi attorno al richiamo automatico ne fanno un'espressione valida. Inoltre valuta a indefinito.

Non penso che esista un modo "giusto" per 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 nei parents che contengono la funzione". – XP1

+26

In realtà non sei limitato a questi due, puoi usare praticamente tutto ciò che fa capire al compilatore che la funzione è parte di un'espressione e non un'istruzione, come '+ function() {}()' o '! Function () {}() '. – Tgr

+45

@ XP1: JSLint vuole molte cose che sono specifiche per lo * stile * di Crockford piuttosto che essere sostanziali. Questo è uno di loro. –

13

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

Non ci sono altri casi di più, ovviamente, utili per invocare espressioni che volontà di funzioni:

(foo || bar)() 
+3

Per chiarimenti ad altri lettori (principalmente perché non l'ho capito prima io :) :), foo e/o bar devono essere già uguali funzione. (ad esempio 'foo = function() {alert ('hi');}'. Se nessuno dei due è una funzione, viene generato un errore –

+2

@AlexanderBird Un ulteriore chiarimento - Si genererà anche un errore se 'foo' è" vero "ma non una funzione. – JLRishe

7

Non c'è alcuna differenza al di là della sintassi.

quanto riguarda le vostre preoccupazioni per il secondo metodo di farlo:

considerare:

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

namedfunc non sarà ancora in 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 del paren.

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

Le parentesi esterne sono inutili:

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

Ma non volevano che la dichiarazione globale in ogni modo, vero?

Così tutto si riduce a:

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

E è possibile ridurre ancora di più: il nome non è necessario dal momento che non sarà mai utilizzato (a meno che la vostra funzione è ricorsiva .. e anche allora si potrebbe usare arguments.callee)

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

Questo è il mio modo di pensare su di esso (non può essere corretto, non ho ancora letto le specifiche ECMAScript). Spero che sia d'aiuto.

-3

La differenza esiste solo perché a Douglas Crockford non piace il primo stile per IIFEs! (seriuosamente) As you can see in this video!!.

L'unica ragione per l'esistenza della confezione in più () {} in entrambi gli stili è quello di contribuire a rendere quella sezione di codice funzione Espressione, perché Dichiarazione funzione non può essere chiamato immediatamente. Alcuni script/minify-ers usano solo +, !, - & ~ invece di parentesi troppo. In questo modo:

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

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

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

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

E tutte queste sono esattamente le stesse delle vostre alternative. La scelta tra questi casi è completamente da solo & non fa differenza. {Quelli con () producono 1 byte più grande File ;-)}

Problemi correlati