2011-09-07 5 views
5

Il codice in questione è semplice:Qual è la spiegazione di questo comportamento? (Quando si creano le funzioni?)

console.log("So it begins."); 
foo(); 
function foo() { console.log("In foo()."); } 
console.log("So it ends."); 

Perché foo() eseguire, prima che venga definita (Edit retrospettiva: in Chrome e Safari)?

Ho armeggiato con questo un po ', testando il seguente codice in Chrome, Safari e Firefox:

javascript:foo();function foo() { alert("Oh."); } 

un avviso viene visualizzato in Chrome e Safari, mentre Firefox rimane in silenzio.

C'è qualche spiegazione per questo comportamento sorprendente e incoerente?

+0

Qual è l'uscita della console? – wosis

risposta

3

Mentre altri hanno spiegato il "sollevamento" il comportamento di funzioni (che personalmente trovo definendolo preparazione contesto o pre-elaborazione più chiaro di sollevamento) la ragione del diverso comportamento di Firefox rimane senza risposta.

Per iniziare, è necessario conoscere la differenza tra una dichiarazione di funzione e una dichiarazione di funzione .

una dichiarazione di funzione, come nel tuo esempio può avvenire solo in due luoghi, nel codice globale (al di fuori di qualsiasi funzione) e direttamente all'interno del corpo della funzione di un'altra funzione, ad esempio:

function foo() {} 

function bar() { 
    function baz() {} 
} 

Tutto il le funzioni di cui sopra sono dichiarazioni di funzioni valide.

L'ECMAScript Specification non permette di definire dichiarazioni di funzioni in altri luoghi, ad esempio all'interno di blocchi:

if (true) { 
    function foo() {} 
} 

La funzione di cui sopra dovrebbe dare un'eccezione SyntaxError, ma la maggior parte delle implementazioni sono benevoli, e loro continuerà a pre-elaborare (sollevare) la funzione, anche se la funzione effettiva non è raggiungibile (ad es. if (false) { function bar() {} }).

In Firefox, dichiarazioni di funzione sono permessi, il che significa che la definizione di funzione in realtà accade quando il controllo raggiunge questa affermazione specifico, ad esempio:

if (true) { 
    function foo() { return true; } 
} else { 
    function foo() { return false; } 
} 

Esecuzione foo(); dopo le dichiarazioni di cui sopra, in Firefox produrrà true, perché il primo ramo dell'istruzione if viene effettivamente eseguito.

In altri browser, foo(); produce false poiché tutte le funzioni sono pre-elaborati quando si entra nel contesto di esecuzione, e l'ultima avrà la precedenza, anche se il ramo false dell'istruzione if è mai raggiunto.

La console di Firebug, esegue il suo codice avvolgendolo all'interno di un blocco try-catch, è per questo che la funzione non è disponibile prima sua dichiarazione.

Se provate sulla console:

console.log(typeof f); // "undefined" 
function f() {} 

vedrete che f non è ancora pronto, ma se si avvolge il codice all'interno di una funzione, si vedrà il comportamento previsto:

(function() { 
    console.log(typeof f); // "function" 
    function f() {} 
})(); 

Anche in questo caso, ora f è definito come una dichiarazione di funzione, poiché esiste nel corpo della funzione anonima e non fa parte di un'istruzione Blocco.

+0

Grazie per lo sforzo compiuto per rompere questo, apprezzalo. – maligree

8

Le delarazioni Javascript verranno sempre spostate in alto. Si chiama sollevamento:

Esempio che dovrebbe funzionare in tutti i browser: http://jsbin.com/abelus/edit

+2

Innanzitutto, grazie. In secondo luogo, no, non funziona allo stesso modo in tutti i browser, almeno al momento della scrittura. Ho testato il codice di esempio che hai collegato su Firefox 6.0.2 e non viene visualizzato "ciao". – maligree

+0

@maligree, questo mi ha davvero sorpreso. Questo esempio funziona in Firefox 6: http://jsbin.com/abelus/2/edit. Sembra essere un problema con jsbin. jsFiddle funziona: http://jsfiddle.net/vVhAc/ – binarious

3

Il il comportamento che stai notando si chiama function hoisting.

In poche parole, le funzioni definite utilizzando la sintassi function foo() { ... } vengono "issate" nella parte superiore dell'ambito in cui sono definite, consentendo in tal modo di essere richiamate prima di essere definite.

Con ciò detto, questa è una parte oscura di JavaScript. Non mi sorprenderebbe se ci fossero differenze nel modo in cui i browser lo implementano (in particolare se si sta utilizzando una versione precedente di firefox).

+0

+1 per il sollevamento, -1 per l'esempio; la ricorsione funziona perché l'esistenza di 'bar()' e 'foo()' viene rilevata in fase di esecuzione (ad es. quando si chiamano le funzioni 'bar' e' pippo'.) – Matt

+0

@ Matt, beh, sarò dannato. Hai ragione. Immagino che rimuoverò l'esempio :) – riwalk

Problemi correlati