Perché non posso utilizzare una funzione Javascript prima della sua definizione all’interno di un blocco try?

Come discusso qui , le definizioni delle funzioni possono essere utilizzate prima che vengano definite. Ma non appena una sezione di codice viene racchiusa in un blocco try, questo non è più il caso.

Questo visualizza “Hello world”:

hello(); function hello() { alert("Hello world"); } 

Ma questo visualizza “ReferenceError: hello non è definito”:

 try { hello(); function hello() { alert("Hello world"); } } catch (err) { alert(err); } 

Quindi, c’è chiaramente qualcosa di “speciale” su un blocco try rispetto alle dichiarazioni di funzione. C’è un modo per aggirare questo comportamento?

Firefox interpreta le istruzioni di funzione in modo diverso e apparentemente hanno rotto la dichiarazione di sollevamento per la dichiarazione di funzione. ( Una buona lettura sulle funzioni con nome / dichiarazione vs espressione )

Perché Firefox interpreta le istruzioni in modo diverso a causa del seguente codice:

 if ( true ) { function test(){alert("YAY");} } else { function test(){alert("FAIL");} } test(); // should alert FAIL 

A causa della dichiarazione di sollevamento, il test funzionamento dovrebbe sempre avvisare “fail”, ma non in Firefox. Il codice sopra in realtà avverte “YAY” in Firefox e sospetto che il codice che lo rende finalmente abbia rotto la dichiarazione di sollevamento del tutto.

Presumo che Firefox trasformi le dichiarazioni di funzioni in dichiarazioni var quando si trovano in if / else o try / catch. Così:

 // firefox interpretted code var test; // hoisted if (true) { test = function(){alert("yay")} } else { test = function(){alert("fail")} } 

Dopo un breve dibattito con Šime Vidas, devo dire che Firefox si occupa di dichiarazioni di funzioni non standard, a causa di:

La produzione SourceElement: l’istruzione viene elaborata per le dichiarazioni di funzione senza eseguire alcuna azione .
La produzione SourceElement: dichiarazione viene valutata come segue:

  1. Valuta la dichiarazione.
  2. Restituisci risultato (1).

Sia FunctionDeclaration che Statement sono SourceElements, ergo, non ci dovrebbero essere FunctionDeclarations all’interno di un’istruzione (if / else, try / catch). Regala a Šime Vidas un biscotto!

Try / catch è fondamentalmente un’altra forma di if / else e probabilmente usa lo stesso codice di eccezione.

Dato che un blocco funzione stabilisce un ambito locale con riferimento a funzioni in avanti, il wrapping del contenuto del blocco try in una funzione immediata sembra ripristinare tale comportamento.

Funziona con Firefox, IE, Chrome:

 try { (function(){ hello(); function hello() { alert("Hello world"); } }()) } catch (err) { alert(err); } 

Naturalmente le funzioni e le variabili definite all’interno della funzione try non sono più visibili nel blocco catch, in quanto sarebbero prive del wrapper funzione immediato. Ma questa è una soluzione alternativa per provare / catturare il wrapping degli script.

Puoi sempre farlo in questo modo e ottenere il meglio da entrambi i mondi:

 function hello() { alert("Hello world"); } try { hello(); } catch (err) { alert(err); } 

Riceverai comunque le tue eccezioni nel blocco catch, ma la funzione sarà disponibile. Dovrebbe essere anche più semplice da mantenere, e non c’è comunque alcun vantaggio funzionale per le funzioni di sollevamento.

Modificare:

Per dimostrare che questo è tanto resistente quanto avvolgere l’intero codice in un tentativo di cattura, sto fornendo un esempio più dettagliato.

 function hello(str) { alert("Hello, " + str); } function greet() { asdf } try { var user = "Bob"; hello(user); greet(); asdf } catch (e) { alert(e); } 

Funzionerà come previsto, senza problemi di analisi. Le uniche posizioni in cui potrebbe fallire al momento del caricamento sono al di fuori della funzione defs e del try catch. Otterrete anche eccezioni su qualsiasi rifiuto all’interno delle funzioni.

Immagino sia una preferenza di stile, ma sembra essere più leggibile e mantenibile per me rispetto ad altre opzioni.