2009-06-18 19 views
410

Qual è la differenza tra le seguenti righe di codice?Qual è la differenza tra un'espressione di funzione e una dichiarazione in JavaScript?

//Function declaration 
function foo() { return 5; } 

//Anonymous function expression 
var foo = function() { return 5; } 

//Named function expression 
var foo = function foo() { return 5; } 
  • Che cosa è un nome/espressione di una funzione anonima?
  • Che cos'è una funzione dichiarata?
  • In che modo i browser gestiscono questi costrutti in modo diverso?

Cosa non corrispondono esattamente le risposte a una domanda simile (var functionName = function() {} vs function functionName() {})?

+0

Ecco [un buon articolo sulle espressioni di funzioni con nome] (http://kangax.github.com/nfe). Le espressioni di funzione e le dichiarazioni sono trattate nella prima sezione. –

+0

La differenza principale IMO sta sollevando. Ecco un buon articolo sull'argomento: http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html –

risposta

10

La prima istruzione dipende dal contesto in cui viene dichiarata.

Se viene dichiarato nel contesto globale, verrà creata una variabile globale implicita denominata "foo" che sarà una variabile che punta alla funzione. Quindi la funzione chiamata "foo()" può essere effettuata ovunque nel tuo programma javascript.

Se si crea la funzione in una chiusura si creerà una variabile locale implicita chiamata "pippo", che è possibile utilizzare per richiamare la funzione all'interno della chiusura con "foo()"

EDIT:

Avrei dovuto anche dire che le istruzioni di funzione (la prima) sono analizzate prima delle espressioni di funzione (Le altre 2). Ciò significa che se dichiari la funzione nella parte inferiore del tuo script, sarai comunque in grado di usarlo nella parte superiore. Le espressioni di funzione vengono valutate solo quando vengono colpite dal codice in esecuzione.

FINE EDIT

Dichiarazioni 2 & 3 sono più o meno equivalenti tra loro. Di nuovo, se usati nel contesto globale, creeranno variabili globali e se usati all'interno di una chiusura creeranno variabili locali. Tuttavia vale la pena notare che la dichiarazione 3 ignorerà il nome della funzione, quindi in modo esenziale si potrebbe chiamare qualsiasi funzione. Pertanto

var foo = function foo() { return 5; } 

è lo stesso di

var foo = function fooYou() { return 5; } 
+19

'fooYou' non viene ignorato. È visibile nel corpo della funzione, quindi la funzione può fare riferimento a se stessa (ad esempio per implementare la ricorsione). –

+1

Questo è un buon punto. Non ci ho pensato :) – Alex

+7

Inoltre, le espressioni di funzione denominate sono utili per il debug: 'var foo = function fooYou() {return 5; }; console.log (foo); console.log (foo.name); 'stampa' fooYou()/fooYou' (Firefox), '[Funzione: fooYou]/fooYou' (node.js),' function fooYou() {return 5; }/fooYou' (Chrome) o qualcosa di solo queste righe, a seconda di dove lo si esegue. – Gilead

335

Sono in realtà molto simili. Il modo in cui li chiami è esattamente lo stesso. La differenza sta nel modo in cui il browser li carica nel contesto di esecuzione.

Le dichiarazioni di funzione vengono caricate prima che venga eseguito qualsiasi codice.

Le espressioni di funzione vengono caricate solo quando l'interprete raggiunge quella riga di codice.

Quindi, se provate a chiamare un'espressione di funzione prima che venga caricata, otterrete un errore! Se si chiama invece una dichiarazione di funzione, funzionerà sempre, poiché non è possibile chiamare alcun codice fino a quando non vengono caricate tutte le dichiarazioni.

Esempio: Funzione Espressione

alert(foo()); // ERROR! foo wasn't loaded yet 
var foo = function() { return 5; } 

Esempio: Dichiarazione di funzione

alert(foo()); // Alerts 5. Declarations are loaded before any code can run. 
function foo() { return 5; } 


Per quanto riguarda la seconda parte della tua domanda:

var foo = function foo() { return 5; } è davvero il sam e come gli altri due. È solo che questa riga di codice ha causato un errore in Safari, anche se non lo è più.

+23

L'ultimo non è la stessa di '' var foo = function() {return 5; } ''. Perché qui '' foo.name'' è '' '' '', nell'ultimo è '' 'foo'''. – JCM

+2

@JCM AFAIK, la proprietà name non fa parte di ECMAScript e viene implementata solo in alcuni browser. ['Function.name' su MDN] (https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/name) –

+7

@ZachL Appena usato come esempio, quello che volevo dire è che la seconda funzione ha un nome, dove il primo non lo fa. – JCM

1

Sebbene la differenza completa sia più complicata, l'unica differenza che mi riguarda è quando la macchina crea l'oggetto funzione. Che nel caso delle dichiarazioni è prima che venga eseguita qualsiasi istruzione, ma dopo che un corpo di dichiarazione è stato invocato (sia che il corpo del codice globale o di una sottofunzione), sia nel caso di espressioni è quando viene eseguita l'istruzione. A parte questo, a tutti gli effetti i browser li trattano allo stesso modo.

per aiutarvi a capire, dare un'occhiata a questa performance test che è stato eliminato un presupposto che avevo fatto delle funzioni dichiarate internamente non ha bisogno di essere ri-creata dalla macchina quando viene richiamata la funzione esterna. Un peccato anche perché mi piaceva scrivere codice in questo modo.

79

Dichiarazione di funzione

function foo() { ... } 

A causa di funzione di sollevamento, la funzione dichiarata in questo modo può essere chiamato sia dopo e prima della definizione.

Funzione Espressione

  1. Nominato Funzione Espressione

    var foo = function bar() { ... } 
    
  2. Anonymous Funzione Espressione

    var foo = function() { ... } 
    

foo() può essere chiamato solo dopo la creazione.

Immediately-Invoked Function Expression (IIFE)

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

Conclusione

Crockford raccomanda di usare l'espressione funzione perché rende chiaro che foo è una variabile che contiene un valore di funzione. Bene, personalmente, preferisco usare la Dichiarazione a meno che non ci sia un motivo per Expression.

+9

Benvenuti in Stack Overflow! Grazie per aver postato la tua risposta! Si prega di leggere attentamente le [FAQ sulla promozione di sé] (http://stackoverflow.com/faq#promotion) attentamente. Si noti inoltre che * è * richiesto * di pubblicare un disclaimer ogni volta che si collega al proprio sito/prodotto. –

+1

punto di interesse: js è case-sensitive. I tuoi esempi bloccati non funzionano ;-) –

+1

inoltre, puoi * avere * un nome IIFE: '(funzione myFunc() {...}());' –

17

Per quanto riguarda la terza definizione:

var foo = function foo() { return 5; } 

Ecco un esempio che mostra come utilizzare possibilità di chiamata ricorsiva:

a = function b(i) { 
    if (i>10) { 
    return i; 
    } 
    else { 
    return b(++i); 
    } 
} 

console.log(a(5)); // outputs 11 
console.log(a(10)); // outputs 11 
console.log(a(11)); // outputs 11 
console.log(a(15)); // outputs 15 

Edit: più interessante esempio con chiusure:

a = function(c) { 
return function b(i){ 
    if (i>c) { 
    return i; 
    } 
    return b(++i); 
} 
} 
d = a(5); 
console.log(d(3)); // outputs 6 
console.log(d(8)); // outputs 8 
+7

Non è necessario dichiarare la funzione con un nome diverso per fare è ricorsivo. In effetti, direi che confonde le cose. 'a = function a (i)' e facendo 'return a (++ i)' produce lo stesso risultato – PhilT

+0

Ma usando un nome diverso per la funzione, la variabile illustra il punto in modo più chiaro. Complimenti per aver fornito un esempio per l'utilizzo delle espressioni di funzioni con nome. – gfullam

Problemi correlati