Cosa significano le parentesi che circondano una dichiarazione di object / funzione / class?

Sono nuovo sia per JavaScript che per YUI . Negli esempi di librerie YUI, puoi trovare molti usi di questo costrutto:

(function() { var Dom = YAHOO.util.Dom, Event = YAHOO.util.Event, layout = null, ... })(); 

Penso che l’ultima coppia di parentesi debba eseguire la funzione subito dopo la dichiarazione.

… Ma per quanto riguarda la precedente serie di parentesi che circonda la dichiarazione di funzione?

Penso che sia una questione di scopo; questo è quello di hide all’interno delle variabili le funzioni esterne e, eventualmente, gli oggetti globali. È? Più in generale, quali sono i meccanismi di quelle parentesi?

È una funzione anonima autoeseguibile. La prima serie di parentesi contiene le espressioni da eseguire e la seconda serie di parentesi esegue quelle espressioni.

È un costrutto utile quando si tenta di hide le variabili dallo spazio dei nomi padre. Tutto il codice all’interno della funzione è contenuto nella portata privata della funzione, il che significa che non è ansible accedervi dal di fuori della funzione, rendendolo veramente privato.

Vedere:

http://en.wikipedia.org/wiki/Closure_%28computer_science%29

http://peter.michaux.ca/articles/javascript-namespacing

Andy Hume ha praticamente dato la risposta, voglio solo aggiungere qualche altro dettaglio.

Con questo costrutto si sta creando una funzione anonima con il proprio ambiente di valutazione o chiusura, e quindi si valuta immediatamente. La cosa bella è che puoi accedere alle variabili dichiarate prima della funzione anonima e puoi usare le variabili locali all’interno di questa funzione senza sovrascrivere accidentalmente una variabile esistente.

L’uso della parola chiave var è molto importante, perché in JavaScript ogni variabile è globale per impostazione predefinita, ma con la parola chiave viene creata una nuova variabile con ambito lessicale , ovvero, è visibile dal codice tra le due parentesi . Nel tuo esempio, stai essenzialmente creando brevi alias per gli oggetti nella libreria YUI, ma ha usi più potenti.

Non voglio lasciarvi senza un esempio di codice, quindi inserirò qui un semplice esempio per illustrare una chiusura:

 var add_gen = function(n) { return function(x) { return n + x; }; }; var add2 = add_gen(2); add2(3); // result is 5 

Che cosa sta succedendo qui? Nella funzione add_gen stai creando un’altra funzione che aggiungerà semplicemente il numero n al suo argomento. Il trucco è che nelle variabili definite nella lista dei parametri di funzione si comportano come variabili con scope lessicale, come quelle definite con var .

La funzione restituita è definita tra le parentesi della funzione add_gen in modo che abbia accesso al valore di n anche dopo che la funzione add_gen ha terminato l’esecuzione, motivo per cui si ottengono 5 quando si esegue l’ultima riga dell’esempio.

Con l’aiuto dei parametri di funzione in ambito lessicale, è ansible aggirare i “problemi” derivanti dall’uso di variabili di ciclo in funzioni anonime. Fai un semplice esempio:

 for(var i=0; i<5; i++) { setTimeout(function(){alert(i)}, 10); } 

Il risultato "atteso" potrebbe essere i numeri da zero a quattro, ma si ottengono invece quattro casi di cinque. Ciò accade perché la funzione anonima in setTimeout e il ciclo for utilizzano la stessa variabile i , quindi quando verranno valutate le funzioni, sarò 5.

È ansible ottenere il risultato ingenuo previsto utilizzando la tecnica nella domanda e il fatto, che i parametri di funzione sono in ambito lessicale. (Ho usato questo approccio in un'altra risposta )

 for(var i=0; i<5; i++) { setTimeout( (function(j) { return function(){alert(j)}; })(i), 10); } 

Con la valutazione immediata della funzione esterna si sta creando una variabile completamente indipendente denominata j in ciascuna iterazione e il valore corrente di i verrà copiato in questa variabile, in modo da ottenere il risultato che ci si aspettava ingenuamente dal primo tentativo.

Ti suggerisco di provare a capire l'eccellente tutorial su http://ejohn.org/apps/learn/ per capire meglio le chiusure, è lì che ho imparato molto molto.

… ma per quanto riguarda le precedenti parentesi rotonde che circondano tutte le dichiarazioni delle funzioni?

In particolare, rende JavaScript interpretare il costrutto ‘function () {…}’ come espressione di una funzione anonima incorporata. Se hai omesso le parentesi:

 function() { alert('hello'); }(); 

Si otterrebbe un errore di syntax, perché il parser JS vedrebbe la parola chiave ‘function’ e suppone che si stia avviando un’istruzione di funzione del modulo:

 function doSomething() { } 

… e non puoi avere una dichiarazione di funzione senza un nome di funzione.

le espressioni di funzione e le istruzioni di funzione sono due diversi costrutti che vengono gestiti in modi molto diversi. Sfortunatamente la syntax è quasi identica, quindi non è solo confusione con il programmatore, anche il parser ha difficoltà a dire che intendi!

Si tratta di dare seguito a ciò che Andy Hume e altri hanno detto:

Il ‘()’ che circonda la funzione anonima è l ” operatore di raggruppamento ‘come definito nella sezione 11.1.6 delle specifiche ECMA: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262 .pdf .

Preso testualmente dai documenti:

11.1.6 L’operatore di raggruppamento

La produzione di PrimaryExpression : ( Expression ) viene valutata come segue:

  1. Restituisce il risultato della valutazione di Expression . Questo potrebbe essere di tipo Reference.

In questo contesto la funzione viene considerata come un’espressione.

Alcune considerazioni sull’argomento:

  • La parentesi:

    Il browser (motore / parser) associa la funzione di parola chiave a

     [optional name]([optional parameters]){...code...} 

    Quindi in un’espressione come function () {} () l’ultima parentesi non ha senso.

    Adesso pensa a

     name=function(){} ; name() !? 

Sì, la prima coppia di parentesi costringe la funzione anonima a trasformarsi in una variabile (espressione memorizzata) e la seconda avvia la valutazione / l’esecuzione, quindi ( function () {} ) () ha senso.

  • L’utilità:?

    1. Per eseguire del codice sul carico e isolare le variabili utilizzate dal resto della pagina, specialmente quando sono possibili conflitti di nome;

    2. Sostituisci eval (“stringa”) con

      (nuova funzione (“stringa”)) ()

    3. Avvolgi il codice lungo per l’operatore ” = ?: ” come:

      risultato = exp_to_test? (function () {… long_code …}) (): (function () {…}) ();

Le prime parentesi sono per, se vuoi, ordine delle operazioni. Il “risultato” dell’insieme di parentesi che circonda la definizione della funzione è la funzione stessa che, in effetti, viene eseguita la seconda serie di parentesi.

Per quanto riguarda il motivo per cui è utile, non sono abbastanza di un wizard JavaScript per avere qualche idea. : P

Vedi questa domanda La prima serie di parentesi non è necessaria se si utilizza un nome di funzione, ma una funzione senza nome richiede questo costrutto e la parentesi serve ai programmatori per rendersi conto di aver visualizzato una funzione auto-invocante durante la navigazione del codice (vedere la migliore di un blogger -prassi di raccomandazione ).