2012-04-10 11 views
46

Eventuali duplicati:
JavaScript: var functionName = function() {} vs function functionName() {}Le funzioni con nome o le funzioni anonime sono preferite in JavaScript?

Ci sono due metodi possibili per tirare fuori una funzione in Javascript:

var foo = function() { ... } 

(questo è un po 'forzato, un altro modello comune is:

var foo = { 
    baz: 43, 
    doSomething:function() { 
     ... 
    } 
} 

)

contro

function foo() { ... } 

C'è un motivo esplicito di preferire l'uno o l'altro?

+0

L'ambito del primo differisce dal secondo? –

+0

Questo è un bell'articolo http://kangax.github.com/nfe/ –

+0

@amnotiam: concordato. Votato per chiudere. –

risposta

66

Tutto si riduce alla preferenza in cui si dichiarano le proprie funzioni; sollevamento.

Le dichiarazioni di funzione e le dichiarazioni di variabile vengono sempre spostate ("sollevate") in modo invisibile nella parte superiore del relativo ambito di contenimento dall'interprete JavaScript. Parametri di funzione e nomi definiti dalla lingua sono, ovviamente, già lì. Ciò significa che il codice come questo:

function foo() { 
    bar(); 
    var x = 1; 
} 

è effettivamente interpretati come questo:

function foo() { 
    var x; 
    bar(); 
    x = 1; 
} 

noti che la porzione assegnazione delle dichiarazioni non sono state innalzate. Solo il nome è issato. Questo non è il caso delle dichiarazioni di funzioni, dove verrà anche issato l'intero corpo della funzione.

function test() { 
    foo(); // TypeError "foo is not a function" 
    bar(); // "this will run!" 
    var foo = function() { // function expression assigned to local variable 'foo' 
     alert("this won't run!"); 
    } 
    function bar() { // function declaration, given the name 'bar' 
     alert("this will run!"); 
    } 
} 
test(); 

In questo caso, solo la dichiarazione di funzione ha il suo corpo issata all'inizio. Il nome 'foo' viene issato, ma il corpo viene lasciato indietro, da assegnare durante l'esecuzione.

È possibile assegnare nomi alle funzioni definite nelle espressioni di funzione, con la sintassi come una dichiarazione di funzione. Questo non lo rende una dichiarazione di funzione, e il nome non è portato nel campo di applicazione, né il corpo è issato.

foo(); // TypeError "foo is not a function" 
bar(); // valid 
baz(); // TypeError "baz is not a function" 
bin(); // ReferenceError "bin is not defined" 

var foo = function() {}; // anonymous function expression ('foo' gets hoisted) 
function bar() {}; // function declaration ('bar' and the function body get hoisted) 
var baz = function bin() {}; // named function expression (only 'baz' gets hoisted) 

foo(); // valid 
bar(); // valid 
baz(); // valid 
bin(); // ReferenceError "bin is not defined" 

Quindi, se la vostra preferenza è di avere funzioni issare all'inizio Utilizzare un function declaration altrimenti utilizzare expression. Preferisco quest'ultimo dato che in genere realizzo letterali di oggetti con metodi come function expressions.

Denominato function expressions può essere utile quando vengono generati errori. La console ti dirà quale sia la funzione invece di indicare anonymous alias stack trace.

+4

Ricorda che le dichiarazioni di funzione nei blocchi sono [tecnicamente non valide] (http://stackoverflow.com/questions/4071292/may-function-declarations-appear-inside-statements-in-javascript), quindi potrebbe essere preferibile utilizzare espressioni di funzione quindi. –

+1

Wow, è così ovvio che "dichiarazioni di funzioni" non dovrebbero esistere/essere trattate specialmente in javascript - dovrebbero essere solo un'espressione, come "espressione di una funzione denominata", il cui valore di ritorno è ignorato. – masterxilo

+0

@ JesseGood-ah si, intendo dentro * se * blocchi. Lo aggiusterò. – RobG

3

ci sono pochi vantaggi alle funzioni di denominazione

  • nomi per meta-analisi. functionInstance.name ti mostrerà il nome.
  • Molto più importante, il nome verrà stampato in tracce dello stack.I nomi
  • aiutano anche a scrivere codice di auto-documentazione o di lettura.

v'è un unico svantaggio per funzioni denominate espressioni

  • IE ha perdite di memoria per NFE

Non ci sono svantaggi per funzionare dichiarazioni a parte meno controllo stilistico

+0

Quale versione (s) di IE? 9? –

+0

IE <9. I vecchi motori JScript, anche Saf 2.1, Old opera, vecchio firefox. Leggi l'articolo NFE – Raynos

0

tuo la domanda in realtà comprende due parti, poiché non è necessario che le funzioni siano anonime se vengono assegnate a una variabile o a una proprietà.

Nome vs anonimo?

@Raynos evidenzia chiaramente i punti principali. La parte migliore delle funzioni con nome è che si mostreranno in una traccia stack. Anche nelle situazioni in cui le funzioni vengono assegnate a variabili/proprietà, è una buona idea assegnare un nome alle funzioni solo per facilitare il debug, tuttavia non direi che le funzioni anonime sono malvagie. Fanno servono una multa scopo: dichiarazione

Are anonymous functions a bad practice in JavaScript?

Funzione vs espressione di una funzione?

Per la parte della questione vi rimando a questa domanda come probabilmente copre l'argomento di gran lunga più approfondita di quanto io possa

var functionName = function() {} vs function functionName() {}

9

hai colpito su un paio di cose diverse qui , ma proverò a rispondere per prima cosa alla tua domanda principale.

In generale ....

function() { ... } è un'espressione funzione di. Sintatticamente questo è allo stesso livello di 2 o [4,5]. Questo rappresenta un valore . Così facendo var foo=function(){ ... } funzionerà come pianificato, ogni volta.

function foo() { ... } è una dichiarazione di funzione. Questo potrebbe sembrare fare la stessa cosa di var foo=function(){...}, ma c'è un piccolo avvertimento. Essendo una dichiarazione, funziona in modo simile al concetto di sollevamento variabile in JS (in pratica tutte le dichiarazioni delle variabili vengono eseguite prima che qualsiasi espressione venga valutata).

Un buon esempio è da here:

function test() { 
    foo(); // TypeError "foo is not a function" 
    bar(); // "this will run!" 
    var foo = function() { // function expression assigned to local variable 'foo' 
     alert("this won't run!"); 
    } 
    function bar() { // function declaration, given the name 'bar' 
     alert("this will run!"); 
    } 
} 
test(); 

sollevamento Fondamentalmente variabile ha portato il valore fino alla cima, quindi questo codice è equivalente (in teoria) a:

function test() { 
    var foo;//foo hoisted to top 
    var bar=function(){//this as well 
     alert("this will run!"); 
    } 

    foo(); // TypeError "foo is not a function" 
    bar(); // "this will run!" 
    var foo = function() { // function expression assigned to local variable 'foo' 
     alert("this won't run!"); 
    } 
} 

NB: Mi piacerebbe prendere questo punto per dire che gli interpreti JS hanno difficoltà a seguire la teoria, quindi fidarsi di loro su un comportamento un po 'incerto r non è raccomandatoHere troverai un buon esempio alla fine di una sezione in cui teoria e pratica finiscono per non funzionare (ci sono anche alcuni dettagli sull'argomento delle espressioni vs dichiarazioni).

Fun fatto: avvolgendo function foo() {...} tra parentesi la trasforma da una dichiarazione ad un'espressione, che può portare a qualche codice cercando strano come

(function foo() { return 1; })();// 1 
foo; //ReferenceError: foo is not defined 

Non farlo se non si dispone di un motivo per , per favore.


Sommariovar foo=function(){ ... } è * sorta pò * la stessa funzione di foo(){ ... } tranne che il primo fa quello che pensi lo fa in cui si pensa che dovrebbe, mentre la seconda fa cose strane a meno che non avvolgerlo in parentesi, ma gli interpreti JS ti permettono di fare cose che sono considerate errori di sintassi nelle specifiche così sei portato a credere che le cose sbagliate siano di fatto giuste, ecc ....

per favore usa la funzione espressioni (var f=function(){...}). Non c'è una vera ragione per non farlo, specialmente considerando che sei un po 'forzato a farlo quando usi la sintassi del punto.


On per la seconda cosa hai toccato .....

Io non sono davvero sicuro di cosa dire, è un po sorta completamente diverso da tutto il resto di questo.

var foo = { 
    baz: 43, 
    doSomething:function() { 
     ... 
    } 
} 

questo è noto come sintassi letterale dell'oggetto. JSON, che si basa su questa sintassi, è a pretty neat way of formatting data e questa sintassi in JS viene spesso utilizzata per dichiarare nuovi oggetti, ad esempio con oggetti singleton (evitando tutto il casino con la dichiarazione di una funzione e l'utilizzo di new). Può essere utilizzato anche nello stesso modo in cui viene utilizzato XML, ed è preferito da parte di tutti i bambini freschi ...

In ogni modo, in sostanza oggetto la sintassi letterale funziona così:

{ name1: val1, .... namek:valk } 

questa espressione è un oggetto con alcuni valori inizializzati su di esso. Così facendo var obj={ name1: val1, .... namek:valk } significa che:

obj.name1==val1; 
obj['name1']==val1;// x['y'] is the same thing as x.y 
... 
obj.namek==valk; 

Così che cosa questo ha a che fare con il nostro esempio? Fondamentalmente la tua espressione è spesso usata per dichiarare oggetti singleton. Ma può anche essere usato per dichiarare un prototipo di oggetto, quindi qualcuno può in seguito var newObj = Object.create (foo), e newObj avrà foo come prototipo.

Analizzare l'ereditarietà del prototipo in dettaglio se si desidera ottenere veramente quanto sia utile. Douglas Crockford ne parla in dettaglio nel one dei suoi numerosi discorsi).

+0

L'esempio 'var foo = {...' non è la sintassi JSON. È la sintassi letterale dell'oggetto. Le notazioni sulla struttura dati di JSON sono * basate su * strutture di oggetti e array letterali di JavaScript, ma non sono la stessa cosa. –

+0

notato, ho provato a cambiare i riferimenti a JSON correttamente. Hai un esempio di JSON che non è una sintassi letterale valida, o viceversa? – rtpg

+0

In genere, se si sta definendo un oggetto letterale nel codice JavaScript, non si fa riferimento ad esso come JSON, poiché il resto del codice JS lo rende JSON non valido. Al contrario, se rimuoviamo tutto il JS, e abbiamo solo una struttura JSON standalone come '{" foo ":" bar "}' (poiché le chiavi JSON devono essere doppie), questo non costituisce un programma JavaScript valido. Il risultato sarà un * SyntaxError *. Inoltre, ci sono alcuni caratteri invisibili che sono consentiti nelle stringhe JavaScript, ma non JSON. Nel complesso, l'unica connessione tra JS e JSON sono le prime due lettere e la sintassi * general * delle strutture dati. –

Problemi correlati