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


6876

Di recente ho iniziato a mantenere il codice JavaScript di qualcun altro. Sto correggendo i bug, aggiungendo funzionalità e anche cercando di riordinare il codice e renderlo più coerente.

Lo sviluppatore precedente ha usato due modi per dichiarare le funzioni e non riesco a capire se c'è un motivo dietro o no.

I due modi sono:

var functionOne = function() {
    // Some code
};
function functionTwo() {
    // Some code
}

Quali sono i motivi per utilizzare questi due diversi metodi e quali sono i pro e i contro di ciascuno? C'è qualcosa che può essere fatto con un metodo che non può essere fatto con l'altro?


198
permadi.com/tutorial/jsFunc/index.html è un'ottima pagina sulle funzioni javascript
uzay95

67
Correlato è questo eccellente articolo sulle espressioni di funzioni denominate .
Phrogz,

12
@CMS fa riferimento a questo articolo: kangax.github.com/nfe/#expr-vs-decl
Upperstage

106
Ci sono due cose di cui devi essere consapevole: # 1 In JavaScript, le dichiarazioni vengono sollevate. Significato che var a = 1; var b = 2;diventa var a; var b; a = 1; b = 2. Pertanto, quando si dichiara functionOne, viene dichiarato ma il suo valore non viene impostato immediatamente. Considerando che poiché la funzione Due è solo una dichiarazione, viene messa in cima all'ambito. Funzione # 2 Due consente di accedere alla proprietà name e questo aiuta molto quando si tenta di eseguire il debug di qualcosa.
xavierm02,

65
Oh e btw, la sintassi corretta è con un ";" dopo l'assegnazione e senza dopo la dichiarazione. Ad esempio function f(){}vs var f = function(){};.
xavierm02,

Risposte:


5045

La differenza è che functionOneè un'espressione di funzione e quindi definita solo quando viene raggiunta quella linea, mentre functionTwoè una dichiarazione di funzione e viene definita non appena viene eseguita la sua funzione o script circostante (a causa del sollevamento ).

Ad esempio, un'espressione di funzione:

// TypeError: functionOne is not a function
functionOne();

var functionOne = function() {
  console.log("Hello!");
};

E una dichiarazione di funzione:

// Outputs: "Hello!"
functionTwo();

function functionTwo() {
  console.log("Hello!");
}

Storicamente, le dichiarazioni di funzione definite all'interno di blocchi venivano gestite in modo incoerente tra i browser. La modalità Strict (introdotta in ES5) ha risolto questo problema dichiarando le dichiarazioni delle funzioni nel loro blocco allegato.

'use strict';    
{ // note this block!
  function functionThree() {
    console.log("Hello!");
  }
}
functionThree(); // ReferenceError


632
@Greg: A proposito, la differenza non è solo che vengono analizzati in momenti diversi. In sostanza, la tua functionOneè semplicemente una variabile a cui è assegnata una funzione anonima, mentre in functionTworealtà è una funzione denominata. Chiama .toString()entrambi per vedere la differenza. Ciò è significativo in alcuni casi in cui si desidera ottenere il nome di una funzione a livello di codice.
Jason Bunting il

6
@ Jason Bunting .. non sicuro di quello che stai ricevendo a qui, .toString () sembra tornare sostanzialmente lo stesso valore (la definizione di funzione) per entrambi: cl.ly/2a2C2Y1r0J451o0q0B1B
Jon z

124
Ci sono entrambi diversi. Il primo è un function expressionsecondo è un function declaration. Puoi leggere di più sull'argomento qui: javascriptweblog.wordpress.com/2010/07/06/…
Michal Kuklis

127
@Greg La parte della risposta relativa al tempo di analisi e al tempo di esecuzione non è corretta. In JavaScript, le dichiarazioni di funzione non sono definite durante il tempo di analisi, ma durante il tempo di esecuzione. Il processo procede in questo modo: viene analizzato il codice sorgente -> viene valutato il programma JavaScript -> viene inizializzato il contesto di esecuzione globale -> viene eseguita l'istanza di associazione della dichiarazione. Durante questo processo vengono istanziate le dichiarazioni delle funzioni (vedere il passaggio 5 del Capitolo 10.5 ).
Šime Vidas

102
La terminologia per questo fenomeno è nota come sollevamento.
Colin Pear,

1943

Per prima cosa voglio correggere Greg: function abc(){}è anch'esso con ambito - il nome abcè definito nell'ambito in cui si incontra questa definizione. Esempio:

function xyz(){
  function abc(){};
  // abc is defined here...
}
// ...but not here

In secondo luogo, è possibile combinare entrambi gli stili:

var xyz = function abc(){};

xyzverrà definito come al solito, abcnon è definito in tutti i browser ma Internet Explorer - non fare affidamento sul fatto che sia definito. Ma sarà definito all'interno del suo corpo:

var xyz = function abc(){
  // xyz is visible here
  // abc is visible here
}
// xyz is visible here
// abc is undefined here

Se si desidera alias funzioni su tutti i browser, utilizzare questo tipo di dichiarazione:

function abc(){};
var xyz = abc;

In questo caso, entrambi xyze abcsono alias dello stesso oggetto:

console.log(xyz === abc); // prints "true"

Un motivo convincente per utilizzare lo stile combinato è l'attributo "nome" degli oggetti funzione ( non supportato da Internet Explorer ). Fondamentalmente quando si definisce una funzione come

function abc(){};
console.log(abc.name); // prints "abc"

il suo nome viene assegnato automaticamente. Ma quando lo definisci come

var abc = function(){};
console.log(abc.name); // prints ""

il suo nome è vuoto: abbiamo creato una funzione anonima e l'abbiamo assegnata a qualche variabile.

Un altro buon motivo per usare lo stile combinato è usare un breve nome interno per riferirsi a se stesso, fornendo allo stesso tempo un nome lungo non in conflitto per gli utenti esterni:

// Assume really.long.external.scoped is {}
really.long.external.scoped.name = function shortcut(n){
  // Let it call itself recursively:
  shortcut(n - 1);
  // ...
  // Let it pass itself as a callback:
  someFunction(shortcut);
  // ...
}

Nell'esempio sopra possiamo fare lo stesso con un nome esterno, ma sarà troppo ingombrante (e più lento).

(Un altro modo di fare riferimento a se stesso è l'uso arguments.callee, che è ancora relativamente lungo e non supportato in modalità rigorosa.)

In fondo, JavaScript tratta entrambe le affermazioni in modo diverso. Questa è una dichiarazione di funzione:

function abc(){}

abc qui è definito ovunque nell'ambito attuale:

// We can call it here
abc(); // Works

// Yet, it is defined down there.
function abc(){}

// We can call it again
abc(); // Works

Inoltre, è stato sollevato attraverso returnun'affermazione:

// We can call it here
abc(); // Works
return;
function abc(){}

Questa è un'espressione di funzione:

var xyz = function(){};

xyz qui è definito dal punto di assegnazione:

// We can't call it here
xyz(); // UNDEFINED!!!

// Now it is defined
xyz = function(){}

// We can call it here
xyz(); // works

La dichiarazione di funzione vs. espressione di funzione è la vera ragione per cui c'è una differenza dimostrata da Greg.

Fatto divertente:

var xyz = function abc(){};
console.log(xyz.name); // Prints "abc"

Personalmente, preferisco la dichiarazione "espressione di funzione" perché in questo modo posso controllare la visibilità. Quando definisco la funzione come

var abc = function(){};

So di aver definito la funzione localmente. Quando definisco la funzione come

abc = function(){};

So di averlo definito a livello globale a condizione che non lo definissi in abcnessun punto della catena degli ambiti. Questo stile di definizione è resistente anche se usato all'interno eval(). Mentre la definizione

function abc(){};

dipende dal contesto e può lasciarti indovinare dove è effettivamente definito, specialmente nel caso di eval()- la risposta è: dipende dal browser.


69
Mi riferisco a RoBorg ma non si trova da nessuna parte. Semplice: RoBorg === Greg. Ecco come la storia può essere riscritta nell'era di Internet. ;-)
Eugene Lazutkin,

10
var xyz = funzione abc () {}; console.log (xyz === abc); Tutti i browser che ho testato (Safari 4, Firefox 3.5.5, Opera 10.10) mi danno "Variabile non definita: abc".
NVI

7
Nel complesso, penso che questo post faccia un buon lavoro nel spiegare le differenze e i vantaggi dell'utilizzo della dichiarazione di funzione. Accetterò di non essere d'accordo per quanto riguarda i vantaggi dell'utilizzo delle assegnazioni di espressioni di funzione a una variabile, soprattutto perché il "vantaggio" sembra essere una promozione della dichiarazione di un'entità globale ... e tutti sanno che non dovresti ingombrare lo spazio dei nomi globale , giusto? ;-)
natlee75

83
imo un grande motivo per usare la funzione nominata è perché i debugger possono usare il nome per aiutarti a dare un senso al tuo stack di chiamate o traccia di stack. fa schifo quando guardi lo stack di chiamate e vedi "funzione anonima" 10 livelli di profondità ...
capra

3
var abc = function(){}; console.log(abc.name);non produce ""più, ma "abc"invece.
Qwerty,

632

Ecco il riassunto delle forme standard che creano funzioni: (Originariamente scritto per un'altra domanda, ma adattato dopo essere stato spostato nella domanda canonica.)

Condizioni:

La lista rapida:

  • Dichiarazione di funzione

  • functionEspressione "anonima" (che nonostante il termine, a volte crea funzioni con nomi)

  • functionEspressione nominata

  • Inizializzatore funzioni accessori (ES5 +)

  • Arrow Function Expression (ES2015 +) (che, come le espressioni di funzioni anonime, non implicano un nome esplicito e tuttavia possono creare funzioni con nomi)

  • Dichiarazione di metodo nell'inizializzatore di oggetti (ES2015 +)

  • Dichiarazioni del costruttore e del metodo in class(ES2015 +)

Dichiarazione di funzione

Il primo modulo è una dichiarazione di funzione , che assomiglia a questo:

function x() {
    console.log('x');
}

Una dichiarazione di funzione è una dichiarazione ; non è un'affermazione o espressione. Come tale, non lo segui con un ;(anche se farlo è innocuo).

Una dichiarazione di funzione viene elaborata quando l'esecuzione entra nel contesto in cui appare, prima che venga eseguito qualsiasi codice passo-passo. Alla funzione che crea viene assegnato un nome proprio ( xnell'esempio sopra) e quel nome viene inserito nell'ambito in cui appare la dichiarazione.

Poiché viene elaborato prima di qualsiasi codice passo-passo nello stesso contesto, puoi fare cose del genere:

x(); // Works even though it's above the declaration
function x() {
    console.log('x');
}

Fino ES2015, la specifica non copriva quello che un motore JavaScript dovrebbe fare se si mette una dichiarazione di funzione all'interno di una struttura di controllo come try, if, switch, while, ecc, in questo modo:

if (someCondition) {
    function foo() {    // <===== HERE THERE
    }                   // <===== BE DRAGONS
}

E poiché vengono elaborati prima dell'esecuzione del codice passo-passo, è difficile sapere cosa fare quando si trovano in una struttura di controllo.

Sebbene ciò non sia stato specificato fino a ES2015, era un'estensione consentita per supportare le dichiarazioni di funzione in blocchi. Sfortunatamente (e inevitabilmente), motori diversi hanno fatto cose diverse.

A partire da ES2015, le specifiche indicano cosa fare. In effetti, offre tre cose separate da fare:

  1. Se in modalità libera non su un browser Web, il motore JavaScript dovrebbe fare una cosa
  2. Se in modalità libera su un browser Web, il motore JavaScript dovrebbe fare qualcos'altro
  3. Se in modalità rigorosa (browser o meno), il motore JavaScript dovrebbe fare ancora un'altra cosa

Le regole per le modalità sciolte sono complicate, ma in modalità rigorosa , le dichiarazioni di funzione nei blocchi sono facili: sono locali per il blocco (hanno un ambito di blocco , che è anche nuovo in ES2015) e sono sollevate all'inizio del blocco. Così:

"use strict";
if (someCondition) {
    foo();               // Works just fine
    function foo() {
    }
}
console.log(typeof foo); // "undefined" (`foo` is not in scope here
                         // because it's not in the same block)

functionEspressione "anonima"

La seconda forma comune si chiama espressione di funzione anonima :

var y = function () {
    console.log('y');
};

Come tutte le espressioni, viene valutata quando viene raggiunta nell'esecuzione passo-passo del codice.

In ES5, la funzione creata non ha nome (è anonima). In ES2015, se possibile, alla funzione viene assegnato un nome deducendolo dal contesto. Nell'esempio sopra, il nome sarebbe y. Qualcosa di simile viene fatto quando la funzione è il valore di un inizializzatore di proprietà. (Per i dettagli su quando questo accade e le regole, cercare SetFunctionNamenella specifica  - appare in tutto il luogo.)

functionEspressione nominata

La terza forma è un'espressione di funzione denominata ("NFE"):

var z = function w() {
    console.log('zw')
};

La funzione che crea ha un nome proprio ( win questo caso). Come tutte le espressioni, questo viene valutato quando viene raggiunto nell'esecuzione passo-passo del codice. Il nome della funzione non viene aggiunto all'ambito in cui appare l'espressione; il nome rientra nell'ambito della funzione stessa:

var z = function w() {
    console.log(typeof w); // "function"
};
console.log(typeof w);     // "undefined"

Si noti che le NFE sono state spesso fonte di bug per le implementazioni JavaScript. IE8 e precedenti, ad esempio, gestiscono gli NFE in modo completamente errato , creando due diverse funzioni in due momenti diversi. Anche le prime versioni di Safari avevano dei problemi. La buona notizia è che le versioni attuali dei browser (IE9 e versioni successive, Safari corrente) non presentano più tali problemi. (Ma al momento della stesura di questo documento, purtroppo, IE8 rimane ampiamente utilizzato, quindi l'utilizzo di NFE con codice per il web in generale è ancora problematico.)

Inizializzatore funzioni accessori (ES5 +)

A volte le funzioni possono insinuarsi in gran parte inosservate; questo è il caso delle funzioni di accesso . Ecco un esempio:

var obj = {
    value: 0,
    get f() {
        return this.value;
    },
    set f(v) {
        this.value = v;
    }
};
console.log(obj.f);         // 0
console.log(typeof obj.f);  // "number"

Nota che quando ho usato la funzione, non l'ho usata ()! Questo perché è una funzione di accesso per una proprietà. Otteniamo e impostiamo la proprietà in modo normale, ma dietro le quinte viene chiamata la funzione.

È inoltre possibile creare accessor funzioni con Object.defineProperty, Object.definePropertiese il meno noto secondo argomento Object.create.

Espressione della funzione freccia (ES2015 +)

ES2015 ci offre la funzione freccia . Ecco un esempio:

var a = [1, 2, 3];
var b = a.map(n => n * 2);
console.log(b.join(", ")); // 2, 4, 6

Vedi quella n => n * 2cosa nascosta nella map()chiamata? Questa è una funzione.

Un paio di cose sulle funzioni delle frecce:

  1. Non hanno il loro this. Invece, hanno stretto sopra la thisdel contesto dove sono definiti. (Si chiudono anche argumentse, se del caso,. super) Ciò significa che l' thisinterno è uguale a quello in thiscui sono stati creati e non può essere modificato.

  2. Come avrai notato con quanto sopra, non usi la parola chiave function; invece, usi =>.

L' n => n * 2esempio sopra è una loro forma. Se hai più argomenti per passare la funzione, usi le parentesi:

var a = [1, 2, 3];
var b = a.map((n, i) => n * i);
console.log(b.join(", ")); // 0, 2, 6

(Ricorda che Array#mappassa la voce come primo argomento e l'indice come secondo.)

In entrambi i casi, il corpo della funzione è solo un'espressione; il valore restituito dalla funzione sarà automaticamente il risultato di quell'espressione (non usi un esplicito return).

Se stai facendo qualcosa di più di una singola espressione, usa {}ed esplicito return(se devi restituire un valore), come di consueto:

var a = [
  {first: "Joe", last: "Bloggs"},
  {first: "Albert", last: "Bloggs"},
  {first: "Mary", last: "Albright"}
];
a = a.sort((a, b) => {
  var rv = a.last.localeCompare(b.last);
  if (rv === 0) {
    rv = a.first.localeCompare(b.first);
  }
  return rv;
});
console.log(JSON.stringify(a));

La versione senza { ... }viene chiamata funzione freccia con un corpo di espressione o corpo conciso . (Inoltre: una funzione freccia concisa .) Quello che { ... }definisce il corpo è una funzione freccia con un corpo funzione . (Inoltre: una funzione freccia dettagliata ).

Dichiarazione di metodo nell'inizializzatore di oggetti (ES2015 +)

ES2015 consente una forma più breve di dichiarazione di una proprietà che fa riferimento a una funzione chiamata definizione del metodo ; sembra così:

var o = {
    foo() {
    }
};

il quasi equivalente in ES5 e precedenti sarebbe:

var o = {
    foo: function foo() {
    }
};

la differenza (oltre alla verbosità) è che un metodo può usare super, ma una funzione non può. Quindi, per esempio, se avessi un oggetto che definisse (diciamo) valueOfusando la sintassi del metodo, avrebbe potuto usare super.valueOf()per ottenere il valore Object.prototype.valueOfsarebbe tornato (prima presumibilmente di fare qualcos'altro con esso), mentre invece la versione ES5 dovrebbe fare Object.prototype.valueOf.call(this).

Ciò significa anche che il metodo ha un riferimento all'oggetto su cui è stato definito, quindi se quell'oggetto è temporaneo (ad esempio, lo si passa Object.assigncome uno degli oggetti di origine), la sintassi del metodo potrebbe significare che l'oggetto viene mantenuto in memoria quando altrimenti avrebbe potuto essere spazzatura raccolta (se il motore JavaScript non rileva quella situazione e gestirla se nessuno dei metodi utilizza super).

Dichiarazioni del costruttore e del metodo in class(ES2015 +)

ES2015 ci porta la classsintassi, inclusi costruttori e metodi dichiarati:

class Person {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    getFullName() {
        return this.firstName + " " + this.lastName;
    }
}

Esistono due dichiarazioni di funzioni sopra: una per il costruttore, che ottiene il nome Persone una per getFullName, a cui è assegnata una funzione Person.prototype.


3
allora il nome wviene semplicemente ignorato?
BiAiB

8
@PellePenna: i nomi delle funzioni sono utili per molte cose. I due biggie a mio avviso sono la ricorsione e il nome della funzione mostrato in stack di chiamate, tracce di eccezione e così via.
TJ Crowder

4
@ChaimEliyah - "Accettare non significa che è la risposta migliore, significa solo che ha funzionato per la persona che ha chiesto." fonte
ScrapCode

6
@AR: Abbastanza vero. In modo divertente, però, proprio sopra che dice "Le migliori risposte vengono visualizzate per prime in modo che siano sempre facili da trovare". Dal momento che la risposta accettata appare prima anche su risposte più votate, il tour potrebbe essere in qualche modo contraddittorio. ;-) Anche un po 'impreciso, se determiniamo "il migliore" in base ai voti (che non è affidabile, è proprio quello che abbiamo), le risposte "migliori" vengono visualizzate prima solo se stai utilizzando la scheda "Voti" - altrimenti, le risposte che sono le prime sono quelle attive o le più vecchie.
TJ Crowder,

1
@TJCrowder: concordato. 'organizzato per data' a volte è fastidioso.
ScrapCode

144

Parlando del contesto globale, sia l' varistruzione che un FunctionDeclarationalla fine creeranno una proprietà non eliminabile sull'oggetto globale, ma il valore di entrambi può essere sovrascritto .

La sottile differenza tra i due modi è che quando viene eseguito il processo di istanza variabile (prima dell'esecuzione effettiva del codice) tutti gli identificatori dichiarati con varverranno inizializzati con undefined, e quelli utilizzati da quelli FunctionDeclarationsaranno disponibili da quel momento, ad esempio:

 alert(typeof foo); // 'function', it's already available
 alert(typeof bar); // 'undefined'
 function foo () {}
 var bar = function () {};
 alert(typeof bar); // 'function'

L'assegnazione del bar FunctionExpressionha luogo fino al runtime.

Una proprietà globale creata da a FunctionDeclarationpuò essere sovrascritta senza problemi proprio come un valore variabile, ad esempio:

 function test () {}
 test = null;

Un'altra ovvia differenza tra i tuoi due esempi è che la prima funzione non ha un nome, ma la seconda ce l'ha, il che può essere davvero utile durante il debug (cioè ispezionare uno stack di chiamate).

Per quanto riguarda il tuo primo esempio modificato ( foo = function() { alert('hello!'); };), si tratta di un compito non dichiarato, ti consiglio vivamente di utilizzare sempre la varparola chiave.

Con un'assegnazione, senza l' varistruzione, se l'identificatore di riferimento non viene trovato nella catena dell'ambito, diventerà una proprietà eliminabile dell'oggetto globale.

Inoltre, le assegnazioni non dichiarate generano un ReferenceErrorECMAScript 5 in modalità Strict .

A deve leggere:

Nota : questa risposta è stata fusa da un'altra domanda , in cui il principale dubbio e malinteso dell'OP era che gli identificatori dichiarati con un FunctionDeclaration, non potevano essere sovrascritti, il che non è il caso.


Non sapevo che le funzioni potevano essere sovrascritte in JavaScript! Inoltre, quell'ordine di analisi è il punto di forza per me. Immagino di dover guardare come creo le funzioni.
Xeoncross,

2
+0 all'articolo "Demistificazione delle espressioni delle funzioni dei nomi" dato che è 404. Possibile specchio ?: kangax.github.com/nfe
Mr_Chimp

@CMS Nice one. Ricorda che non ho mai visto l'originale, quindi non so se si tratta di uno specchio o di un altro articolo con lo stesso titolo!
Mr_Chimp,

@Mr_Chimp Sono abbastanza sicuro che lo sia, thewaybackmachine sta dicendo che ha ottenuto un 302 al momento della ricerca per indicizzazione e il reindirizzamento è stato al collegamento fornito.
John

124

I due frammenti di codice che hai pubblicato lì, per quasi tutti gli scopi, si comporteranno allo stesso modo.

Tuttavia, la differenza nel comportamento è che con la prima variante ( var functionOne = function() {}), quella funzione può essere chiamata solo dopo quel punto nel codice.

Con la seconda variante ( function functionTwo()), la funzione è disponibile per il codice che viene eseguito sopra dove viene dichiarata la funzione.

Questo perché con la prima variante, la funzione viene assegnata alla variabile fooin fase di esecuzione. Nel secondo, la funzione è assegnata a quell'identificatore foo, al momento dell'analisi.

Ulteriori informazioni tecniche

JavaScript ha tre modi per definire le funzioni.

  1. Il tuo primo frammento mostra un'espressione di funzione . Ciò implica l'utilizzo dell'operatore "funzione" per creare una funzione: il risultato di tale operatore può essere archiviato in qualsiasi variabile o proprietà dell'oggetto. L'espressione della funzione è potente in questo modo. L'espressione della funzione è spesso chiamata "funzione anonima", perché non deve avere un nome,
  2. Il tuo secondo esempio è una dichiarazione di funzione . Questo utilizza l' istruzione "function" per creare una funzione. La funzione è resa disponibile al momento dell'analisi e può essere richiamata ovunque in tale ambito. È ancora possibile memorizzarlo in una variabile o proprietà dell'oggetto in un secondo momento.
  3. Il terzo modo di definire una funzione è il costruttore "Function ()" , che non è mostrato nel tuo post originale. Non è consigliabile utilizzare questo in quanto funziona allo stesso modo eval(), che ha i suoi problemi.

103

Una migliore spiegazione alla risposta di Greg

functionTwo();
function functionTwo() {
}

Perché nessun errore? Ci è stato sempre insegnato che le espressioni sono eseguite dall'alto verso il basso (??)

Perché:

Le dichiarazioni di funzioni e dichiarazioni di variabili vengono sempre spostate ( hoisted) in modo invisibile nella parte superiore del loro ambito di contenimento dall'interprete JavaScript. I parametri di funzione e i nomi definiti dalla lingua sono, ovviamente, già presenti. ben ciliegia

Ciò significa che il codice in questo modo:

functionOne();                  ---------------      var functionOne;
                                | is actually |      functionOne();
var functionOne = function(){   | interpreted |-->
};                              |    like     |      functionOne = function(){
                                ---------------      };

Si noti che la parte di assegnazione delle dichiarazioni non è stata sollevata. Viene sollevato solo il nome.

Ma nel caso delle dichiarazioni di funzioni, verrà sollevato anche l'intero corpo della funzione :

functionTwo();              ---------------      function functionTwo() {
                            | is actually |      };
function functionTwo() {    | interpreted |-->
}                           |    like     |      functionTwo();
                            ---------------

Ciao suhail grazie per le informazioni chiare sull'argomento della funzione. Ora la mia domanda è quale sarà la prima dichiarazione nella gerarchia delle dichiarazioni se dichiarazione variabile (functionOne) o dichiarazione funzione (functionTwo)?
Sharathi RB,

91

Altri commentatori hanno già coperto la differenza semantica delle due varianti sopra. Volevo notare una differenza stilistica: solo la variazione di "assegnazione" può impostare una proprietà di un altro oggetto.

Costruisco spesso moduli JavaScript con un modello come questo:

(function(){
    var exports = {};

    function privateUtil() {
            ...
    }

    exports.publicUtil = function() {
            ...
    };

    return exports;
})();

Con questo modello, tutte le funzioni pubbliche utilizzeranno l'assegnazione, mentre le funzioni private utilizzano la dichiarazione.

(Nota anche che l'assegnazione dovrebbe richiedere un punto e virgola dopo la dichiarazione, mentre la dichiarazione la proibisce.)


4
yuiblog.com/blog/2007/06/12/module-pattern è il riferimento primordiale per il modello del modulo, per quanto ne so. (Anche se quell'articolo usa la var foo = function(){...}sintassi anche per variabili private.
Sean McMillan,

Questo non è del tutto vero in alcune versioni precedenti di IE, in realtà. ( function window.onload() {}era una cosa.)
Ry-

77

Un'illustrazione di quando preferire il primo metodo al secondo è quando è necessario evitare di ignorare le definizioni precedenti di una funzione.

Con

if (condition){
    function myfunction(){
        // Some code
    }
}

, questa definizione di myfunctionsovrascriverà qualsiasi definizione precedente, poiché verrà eseguita in fase di analisi.

Mentre

if (condition){
    var myfunction = function (){
        // Some code
    }
}

fa il lavoro corretto di definire myfunctionsolo quando conditionè soddisfatto.


1
questo esempio è buono ed è vicino alla perfezione, ma potrebbe essere migliorato. l'esempio migliore sarebbe definire var myFunc = null;al di fuori di un ciclo o al di fuori di un blocco if / elseif / else. Quindi è possibile assegnare in modo condizionale diverse funzioni alla stessa variabile. In JS, è una convenzione migliore assegnare un valore mancante a null, quindi a indefinito. Pertanto, è necessario dichiarare prima myFunction come null, quindi assegnarlo successivamente, in modo condizionale.
Alexander Mills,

62

Un motivo importante è aggiungere una e una sola variabile come "Root" del tuo spazio dei nomi ...

var MyNamespace = {}
MyNamespace.foo= function() {

}

o

var MyNamespace = {
  foo: function() {
  },
  ...
}

Esistono molte tecniche per la spaziatura dei nomi. È diventato più importante con la pletora di moduli JavaScript disponibili.

Vedi anche Come posso dichiarare uno spazio dei nomi in JavaScript?


3
Sembra che questa risposta sia stata fusa in questa domanda da un'altra domanda e la formulazione potrebbe sembrare un po 'estranea a questa domanda. Considereresti di modificare la risposta in modo che appaia più specificamente indirizzato a questa domanda? (per ribadire; non è affatto colpa tua ... solo un effetto collaterale di una domanda unita). Puoi anche cancellarlo e penso che manterrai la tua reputazione. Oppure puoi lasciarlo; poiché è vecchio, potrebbe non fare una grande differenza.
Andrew Barber,

55

Il sollevamento è l'azione dell'interprete JavaScript di spostare tutte le dichiarazioni di variabili e funzioni in cima all'ambito corrente.

Tuttavia, vengono sollevate solo le dichiarazioni effettive. lasciando gli incarichi dove sono.

  • le variabili / funzioni dichiarate all'interno della pagina sono globali e possono accedere ovunque in quella pagina.
  • Le variabili / funzioni dichiarate all'interno della funzione hanno ambito locale. significa che sono disponibili / accessibili all'interno del corpo della funzione (ambito), non sono disponibili al di fuori del corpo della funzione.

Variabile

Javascript è chiamato linguaggio tipicamente diffuso. Ciò significa che le variabili Javascript possono contenere valori di qualsiasi tipo di dati . Javascript si occupa automaticamente di modificare il tipo di variabile in base al valore / valore letterale fornito durante il runtime.

global_Page = 10;                                               var global_Page;      « undefined
    « Integer literal, Number Type.   -------------------       global_Page = 10;     « Number         
global_Page = 'Yash';                 |   Interpreted   |       global_Page = 'Yash'; « String
    « String literal, String Type.    «       AS        «       global_Page = true;   « Boolean 
var global_Page = true;               |                 |       global_Page = function (){          « function
    « Boolean Type                    -------------------                 var local_functionblock;  « undefined
global_Page = function (){                                                local_functionblock = 777 Number
    var local_functionblock = 777;                              };  
    // Assigning function as a data.
};  

Funzione

function Identifier_opt ( FormalParameterList_opt ) { 
      FunctionBody | sequence of statements

      « return;  Default undefined
      « return 'some data';
}
  • le funzioni dichiarate all'interno della pagina vengono sollevate nella parte superiore della pagina con accesso globale.
  • le funzioni dichiarate all'interno del blocco funzione vengono sollevate nella parte superiore del blocco.
  • Il valore di ritorno predefinito della funzione è ' non definito ', anche il valore predefinito della dichiarazione variabile è 'non definito'

    Scope with respect to function-block global. 
    Scope with respect to page undefined | not available.

Dichiarazione di funzione

function globalAccess() {                                  function globalAccess() {      
}                                  -------------------     }
globalAccess();                    |                 |     function globalAccess() { « Re-Defined / overridden.
localAccess();                     «   Hoisted  As   «         function localAccess() {
function globalAccess() {          |                 |         }
     localAccess();                -------------------         localAccess(); « function accessed with in globalAccess() only.
     function localAccess() {                              }
     }                                                     globalAccess();
}                                                          localAccess(); « ReferenceError as the function is not defined

Espressione di funzione

        10;                 « literal
       (10);                « Expression                (10).toString() -> '10'
var a;                      
    a = 10;                 « Expression var              a.toString()  -> '10'
(function invoke() {        « Expression Function
 console.log('Self Invoking');                      (function () {
});                                                               }) () -> 'Self Invoking'

var f; 
    f = function (){        « Expression var Function
    console.log('var Function');                                   f ()  -> 'var Function'
    };

Funzione assegnata alla variabile Esempio:

(function selfExecuting(){
    console.log('IIFE - Immediately-Invoked Function Expression');
}());

var anonymous = function (){
    console.log('anonymous function Expression');
};

var namedExpression = function for_InternalUSE(fact){
    if(fact === 1){
        return 1;
    }

    var localExpression = function(){
        console.log('Local to the parent Function Scope');
    };
    globalExpression = function(){ 
        console.log('creates a new global variable, then assigned this function.');
    };

    //return; //undefined.
    return fact * for_InternalUSE( fact - 1);   
};

namedExpression();
globalExpression();

javascript interpretato come

var anonymous;
var namedExpression;
var globalExpression;

anonymous = function (){
    console.log('anonymous function Expression');
};

namedExpression = function for_InternalUSE(fact){
    var localExpression;

    if(fact === 1){
        return 1;
    }
    localExpression = function(){
        console.log('Local to the parent Function Scope');
    };
    globalExpression = function(){ 
        console.log('creates a new global variable, then assigned this function.');
    };

    return fact * for_InternalUSE( fact - 1);    // DEFAULT UNDEFINED.
};

namedExpression(10);
globalExpression();

È possibile controllare la dichiarazione di funzione, test di espressione su diversi browser utilizzando jsperf Test Runner


Classi di funzione costruttore ES5 : oggetti funzione creati utilizzando Function.prototype.bind

JavaScript considera le funzioni come oggetti di prima classe, quindi essendo un oggetto, è possibile assegnare proprietà a una funzione.

function Shape(id) { // Function Declaration
    this.id = id;
};
    // Adding a prototyped method to a function.
    Shape.prototype.getID = function () {
        return this.id;
    };
    Shape.prototype.setID = function ( id ) {
        this.id = id;
    };

var expFn = Shape; // Function Expression

var funObj = new Shape( ); // Function Object
funObj.hasOwnProperty('prototype'); // false
funObj.setID( 10 );
console.log( funObj.getID() ); // 10

ES6 ha introdotto la funzione Freccia : un'espressione della funzione Freccia ha una sintassi più breve, sono più adatti per funzioni non metodiche e non possono essere usate come costruttori.

ArrowFunction : ArrowParameters => ConciseBody.

const fn = (item) => { return item & 1 ? 'Odd' : 'Even'; };
console.log( fn(2) ); // Even
console.log( fn(3) ); // Odd

3
ahm, la tua risposta ... non è ambigua? ben scritto però +1 per spendere e scrivere troppe informazioni.
Danese

40

Sto aggiungendo la mia risposta solo perché tutti gli altri hanno approfondito la parte di sollevamento.

Mi chiedo da che parte sia meglio da molto tempo ormai, e grazie a http://jsperf.com ora lo so :)

inserisci qui la descrizione dell'immagine

Le dichiarazioni di funzioni sono più veloci, ed è quello che conta davvero nel web dev giusto? ;)


8
Direi che la manutenibilità è l'aspetto più importante della maggior parte del codice. Le prestazioni sono importanti, ma nella maggior parte dei casi l'IO è probabilmente un maggiore collo di bottiglia rispetto al modo in cui definisci le tue funzioni. Tuttavia, ci sono alcuni problemi in cui sono necessarie tutte le prestazioni che è possibile ottenere e ciò è utile in questi casi. Buono anche avere una risposta qui che risponda chiaramente a una parte ben definita della domanda.
Richard Garside,

3
Bene, l'ho trovato in un altro modo con Firefox. jsperf.com/sandytest
Sandeep Nayak

Solo un aggiornamento, dal momento che sono passato allo stile di programmazione completamente funzionale in JavaScript ora, non uso mai dichiarazioni, solo espressioni di funzioni in modo da poter concatenare e chiamare le mie funzioni con i loro nomi di variabili. Dai un'occhiata a RamdaJS ...
Leon Gaban,

1
@SandeepNayak Ho appena eseguito il tuo test in Firefox 50.0.0 / Windows 7 0.0.0, e in realtà è lo stesso di quello di Leon. Quindi, se il test è corretto, concluderei che i test di jsperf non sono indicativi e tutto dipende dal browser e / o dalla versione del sistema operativo o dallo stato particolare della macchina corrente in quel particolare momento.
Ocramot,

33

Una dichiarazione di funzione e un'espressione di funzione assegnate a una variabile si comportano allo stesso modo dopo aver stabilito l'associazione.

Esiste tuttavia una differenza su come e quando l'oggetto funzione è effettivamente associato alla sua variabile. Questa differenza è dovuta al meccanismo chiamato sollevamento variabile in JavaScript.

Fondamentalmente, tutte le dichiarazioni di funzioni e dichiarazioni di variabili vengono sollevate all'inizio della funzione in cui si verifica la dichiarazione (per questo diciamo che JavaScript ha un ambito di funzione ).

  • Quando viene sollevata una dichiarazione di funzione, il corpo della funzione "segue", quindi quando viene valutato il corpo della funzione, la variabile verrà immediatamente associata a un oggetto funzione.

  • Quando viene sollevata una dichiarazione variabile, l'inizializzazione non segue, ma viene "lasciata indietro". La variabile viene inizializzata undefinedall'inizio del corpo della funzione e verrà assegnato un valore nella posizione originale nel codice. (In realtà, verrà assegnato un valore in ogni posizione in cui si verifica una dichiarazione di una variabile con lo stesso nome.)

Anche l'ordine di sollevamento è importante: le dichiarazioni di funzioni hanno la precedenza sulle dichiarazioni di variabili con lo stesso nome e l'ultima dichiarazione di funzione ha la precedenza sulle dichiarazioni di funzioni precedenti con lo stesso nome.

Qualche esempio...

var foo = 1;
function bar() {
  if (!foo) {
    var foo = 10 }
  return foo; }
bar() // 10

La variabile fooviene sollevata nella parte superiore della funzione, inizializzata su undefined, quindi !fooè truecosì fooassegnata 10. L' fooesterno del barcampo di applicazione non ha alcun ruolo ed è intatto.

function f() {
  return a; 
  function a() {return 1}; 
  var a = 4;
  function a() {return 2}}
f()() // 2

function f() {
  return a;
  var a = 4;
  function a() {return 1};
  function a() {return 2}}
f()() // 2

Le dichiarazioni di funzioni hanno la precedenza sulle dichiarazioni di variabili e l'ultima dichiarazione di funzione "si attacca".

function f() {
  var a = 4;
  function a() {return 1}; 
  function a() {return 2}; 
  return a; }
f() // 4

In questo esempio aviene inizializzato con l'oggetto funzione risultante dalla valutazione della seconda dichiarazione di funzione, quindi viene assegnato 4.

var a = 1;
function b() {
  a = 10;
  return;
  function a() {}}
b();
a // 1

Qui viene prima sollevata la dichiarazione di funzione, dichiarando e inizializzando la variabile a. Successivamente, viene assegnata questa variabile 10. In altre parole: l'assegnazione non viene assegnata alla variabile esterna a.


3
Hai un modo un po 'strano di posizionare le parentesi graffe di chiusura. Sei un programmatore Python? Sembra che tu provi a rendere Javascript simile a Python. Temo che sia fonte di confusione per le altre persone. Se dovessi mantenere il tuo codice JavaScript, lascerei prima che il tuo codice passi attraverso una stampante piuttosto carina.
nalply

1
Post eccellente. Una "funzione auto-esecutiva" o "espressione di funzione immediatamente invocata" dovrebbe essere abbastanza facile da vedere e la sua preferenza di stile non dovrebbe sminuire il suo post - che è accurato e riassume perfettamente il "sollevamento". +1
Ricalsin,

32

Il primo esempio è una dichiarazione di funzione:

function abc(){}

Il secondo esempio è un'espressione di funzione:

var abc = function() {};

La differenza principale è come vengono sollevati (sollevati e dichiarati). Nel primo esempio viene sollevata l'intera dichiarazione di funzione. Nel secondo esempio viene sollevato solo il var 'abc', il suo valore (la funzione) sarà indefinito e la funzione stessa rimarrà nella posizione in cui è stata dichiarata.

Per dirla semplicemente:

//this will work
abc(param);
function abc(){}

//this would fail
abc(param);
var abc = function() {}

Per saperne di più su questo argomento ti consiglio vivamente questo link


1
Il tuo esempio è un po 'lo stesso della risposta principale
GôTô

Il motivo principale per pubblicare questa risposta è stato quello di fornire il link in fondo. Questo era il pezzo che mi mancava per comprendere appieno la domanda di cui sopra.
sla55er,

1
È fantastico che tu abbia voluto condividere il link. Ma i collegamenti a informazioni aggiuntive, in SO, dovrebbero essere solo un commento sulla domanda o sulla tua risposta preferita. È molto non ottimale ingombrare una pagina lunga e complicata come questa con informazioni ripetute solo per aggiungere un singolo link utile alla fine. No, non otterrai punti rep per aver fornito il link, ma aiuterai la community.
XML

31

In termini di costi di manutenzione del codice, le funzioni denominate sono più preferibili:

  • Indipendente dal luogo in cui sono dichiarati (ma ancora limitato dal campo di applicazione).
  • Più resistente agli errori come l'inizializzazione condizionale (se si desidera, è comunque possibile eseguire l'override).
  • Il codice diventa più leggibile allocando le funzioni locali separatamente dalla funzionalità dell'ambito. Solitamente nell'ambito la funzionalità inizia per prima, seguita da dichiarazioni di funzioni locali.
  • In un debugger vedrai chiaramente il nome della funzione nello stack di chiamate anziché una funzione "anonima / valutata".

Sospetto che seguano altri PRO per le funzioni con nome. E ciò che è elencato come un vantaggio delle funzioni con nome è uno svantaggio per quelle anonime.

Storicamente, le funzioni anonime sono apparse dall'impossibilità di JavaScript come lingua per elencare i membri con funzioni denominate:

{
    member:function() { /* How do I make "this.member" a named function? */
    }
}

2
Ci sono i test da confermare: blog.firsov.net/2010/01/… Test delle prestazioni JS - ambito e funzioni nominate - Analytics
Sasha Firsov

25

In termini di informatica, parliamo di funzioni anonime e funzioni denominate. Penso che la differenza più importante sia che una funzione anonima non è legata a un nome, da cui la funzione anonima del nome. In JavaScript è un oggetto di prima classe dichiarato dinamicamente in fase di esecuzione.

Per ulteriori informazioni sulle funzioni anonime e sul calcolo lambda, Wikipedia è un buon inizio ( http://en.wikipedia.org/wiki/Anonymous_function ).


A partire da ES2015 (sei anni e mezzo dopo la pubblicazione della risposta), entrambe le funzioni nella domanda sono denominate.
TJ Crowder

25

Uso l'approccio variabile nel mio codice per un motivo molto specifico, la cui teoria è stata trattata in modo astratto sopra, ma un esempio potrebbe aiutare alcune persone come me, con competenze JavaScript limitate.

Ho un codice che devo eseguire con 160 marchi progettati in modo indipendente. La maggior parte del codice si trova in file condivisi, ma gli elementi specifici del marchio sono in un file separato, uno per ciascun marchio.

Alcuni marchi richiedono funzioni specifiche, altri no. A volte devo aggiungere nuove funzioni per fare nuove cose specifiche del marchio. Sono felice di cambiare il codice condiviso, ma non voglio cambiare tutti i 160 set di file di branding.

Usando la sintassi della variabile, posso dichiarare la variabile (essenzialmente un puntatore a funzione) nel codice condiviso e assegnare una banale funzione di stub o impostare su null.

Una o due marche che richiedono un'implementazione specifica della funzione possono quindi definire la loro versione della funzione e assegnarla alla variabile se lo desiderano, e il resto non fa nulla. Posso verificare una funzione null prima di eseguirla nel codice condiviso.

Dai commenti delle persone sopra, ritengo che possa essere possibile ridefinire anche una funzione statica, ma penso che la soluzione variabile sia chiara e chiara.


25

La risposta di Greg è abbastanza buona, ma vorrei ancora aggiungere qualcosa che ho imparato proprio ora guardando i video di Douglas Crockford .

Espressione di funzione:

var foo = function foo() {};

Dichiarazione di funzione:

function foo() {};

L'istruzione function è solo una scorciatoia per l' varistruzione con afunction valore.

Così

function foo() {};

si espande a

var foo = function foo() {};

Che si espande ulteriormente a:

var foo = undefined;
foo = function foo() {};

E sono entrambi issati in cima al codice.

Schermata dal video


7
Scusa ma non è corretto - non so cosa stia cercando di dire Crockford in quella diapositiva. Le dichiarazioni di funzioni e variabili sono sempre sollevate al di sopra del loro ambito di applicazione. La differenza è che le assegnazioni di variabili (sia che tu le stia assegnando con una stringa, un valore booleano o una funzione) non sono sollevate in alto, mentre lo sono i corpi di funzione (usando la dichiarazione di funzione).
Thomas Heymann,


24

Esistono quattro confronti degni di nota tra le due diverse dichiarazioni di funzioni elencate di seguito.

  1. Disponibilità (ambito) della funzione

Quanto segue funziona perché function add()è limitato al blocco più vicino:

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

function add(a, b){
  return a + b;
}

Quanto segue non funziona perché la variabile viene chiamata prima che un valore di funzione venga assegnato alla variabile add.

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

var add=function(a, b){
  return a + b;
}

Il codice sopra è identico nella funzionalità al codice qui sotto. Nota che l'assegnazione esplicita add = undefinedè superflua perché semplicemente fare var add;è esattamente lo stesso di var add=undefined.

var add = undefined;

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

add = function(a, b){
  return a + b;
}

Quanto segue non funziona perché var add=sostituisce il function add().

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

var add=function add(a, b){
  return a + b;
}

  1. (funzione) .name

Il nome di una funzione function thefuncname(){}è il nome utente quando viene dichiarato in questo modo.

function foobar(a, b){}

console.log(foobar.name);

var a = function foobar(){};

console.log(a.name);

Altrimenti, se una funzione viene dichiarata come function(){}, la funzione .name è la prima variabile utilizzata per memorizzare la funzione.

var a = function(){};
var b = (function(){ return function(){} });

console.log(a.name);
console.log(b.name);

Se non ci sono variabili impostate sulla funzione, il nome della funzione è la stringa vuota ( "").

console.log((function(){}).name === "");

Infine, mentre la variabile a cui è assegnata la funzione imposta inizialmente il nome, le variabili successive impostate sulla funzione non cambiano il nome.

var a = function(){};
var b = a;
var c = b;

console.log(a.name);
console.log(b.name);
console.log(c.name);

  1. Prestazione

In Google V8 e Spidermonkey di Firefox potrebbero esserci alcune differenze nella compilation JIST di un microsecondo, ma alla fine il risultato è esattamente lo stesso. Per dimostrarlo, esaminiamo l'efficienza di JSPerf nei microbenchmark confrontando la velocità di due frammenti di codice vuoti. I test JSPerf sono disponibili qui . E i test jsben.ch sono disponibili qui . Come puoi vedere, c'è una notevole differenza quando non ci dovrebbe essere nessuno. Se sei davvero un maniaco delle prestazioni come me, allora potrebbe valere la pena cercare di ridurre il numero di variabili e funzioni nell'ambito e soprattutto di eliminare il polimorfismo (come usare la stessa variabile per memorizzare due tipi diversi).

  1. Mutabilità variabile

Quando si utilizza la varparola chiave per dichiarare una variabile, è possibile quindi riassegnare un valore diverso alla variabile in questo modo.

(function(){
    "use strict";
    var foobar = function(){}; // initial value
    try {
        foobar = "Hello World!"; // new value
        console.log("[no error]");
    } catch(error) {
        console.log("ERROR: " + error.message);
    }
    console.log(foobar, window.foobar);
})();

Tuttavia, quando usiamo l'istruzione const, il riferimento alla variabile diventa immutabile. Ciò significa che non possiamo assegnare un nuovo valore alla variabile. Si noti, tuttavia, che ciò non rende immutabile il contenuto della variabile: in tal caso const arr = [], è comunque possibile farlo arr[10] = "example". Fare solo qualcosa di simile arr = "new value"o arr = []genererebbe un errore come mostrato di seguito.

(function(){
    "use strict";
    const foobar = function(){}; // initial value
    try {
        foobar = "Hello World!"; // new value
        console.log("[no error]");
    } catch(error) {
        console.log("ERROR: " + error.message);
    }
    console.log(foobar, window.foobar);
})();

È interessante notare che se dichiariamo la variabile come function funcName(){}, allora l'immutabilità della variabile è la stessa di dichiararla con var.

(function(){
    "use strict";
    function foobar(){}; // initial value
    try {
        foobar = "Hello World!"; // new value
        console.log("[no error]");
    } catch(error) {
        console.log("ERROR: " + error.message);
    }
    console.log(foobar, window.foobar);
})();

Qual è il "blocco più vicino"

Il "blocco più vicino" è la "funzione" più vicina (comprese le funzioni asincrone, le funzioni del generatore e le funzioni del generatore asincrono). Tuttavia, è interessante function functionName() {}notare che un si comporta come var functionName = function() {}quando si trova in un blocco di non chiusura ad elementi al di fuori di detta chiusura. Osservare.

  • Normale var add=function(){}

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}');
  }
} catch(e) {
  console.log("Is a block");
}
var add=function(a, b){return a + b}

  • Normale function add(){}

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
function add(a, b){
  return a + b;
}

  • Funzione

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
(function () {
    function add(a, b){
      return a + b;
    }
})();

  • Dichiarazione (come ad esempio if, else, for, while, try/ catch/ finally, switch, do/ while, with)

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
{
    function add(a, b){
      return a + b;
    }
}

  • Funzione freccia con var add=function()

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
(() => {
    var add=function(a, b){
      return a + b;
    }
})();

  • Funzione freccia con function add()

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
(() => {
    function add(a, b){
      return a + b;
    }
})();


Questa merita di essere la risposta accettata e più votata
Aaron John Sabu,

18

@EugeneLazutkin fornisce un esempio in cui nomina una funzione assegnata per poterla utilizzareshortcut() come riferimento interno a se stessa. John Resig fa un altro esempio: copiare una funzione ricorsiva assegnata a un altro oggetto nel suo Javascript avanzato di apprendimento tutorial di . Sebbene l'assegnazione delle funzioni alle proprietà non sia strettamente la domanda qui, ti consiglio di provare attivamente il tutorial: esegui il codice facendo clic sul pulsante nell'angolo in alto a destra e fai doppio clic sul codice per modificarlo a tuo piacimento.

Esempi dal tutorial: chiamate ricorsive in yell() :

I test falliscono quando viene rimosso l'oggetto ninja originale. (pagina 13)

var ninja = { 
  yell: function(n){ 
    return n > 0 ? ninja.yell(n-1) + "a" : "hiy"; 
  } 
}; 
assert( ninja.yell(4) == "hiyaaaa", "A single object isn't too bad, either." ); 

var samurai = { yell: ninja.yell }; 
var ninja = null; 

try { 
  samurai.yell(4); 
} catch(e){ 
  assert( false, "Uh, this isn't good! Where'd ninja.yell go?" ); 
}

Se si nomina la funzione che verrà chiamata in modo ricorsivo, i test passeranno. (pagina 14)

var ninja = { 
  yell: function yell(n){ 
    return n > 0 ? yell(n-1) + "a" : "hiy"; 
  } 
}; 
assert( ninja.yell(4) == "hiyaaaa", "Works as we would expect it to!" ); 

var samurai = { yell: ninja.yell }; 
var ninja = {}; 
assert( samurai.yell(4) == "hiyaaaa", "The method correctly calls itself." );

17

Un'altra differenza che non è menzionata nelle altre risposte è che se si utilizza la funzione anonima

var functionOne = function() {
    // Some code
};

e usalo come costruttore come in

var one = new functionOne();

quindi one.constructor.namenon sarà definito.Function.namenon è standard ma è supportato da Firefox, Chrome, altri browser derivati ​​da Webkit e IE 9+.

Con

function functionTwo() {
    // Some code
}
two = new functionTwo();

è possibile recuperare il nome del costruttore come stringa con two.constructor.name.


Il nome nel primo caso non verrà definito perché è una funzione anonima assegnata a una variabile. Penso che la parola anonimo sia stata inventata per cose che non hanno il loro nome definito :)
Om Shankar

In questo esempio il due = nuovo diventa una funzione globale perché nessuna var
Waqas Tahir

16

Il primo (funzione doSomething (x)) dovrebbe far parte di una notazione oggetto.

La seconda ( var doSomething = function(x){ alert(x);}) è semplicemente creando una funzione anonima e assegnando a una variabile, doSomething. Quindi doSomething () chiamerà la funzione.

Potresti voler sapere quale dichiarazione di funzione ed espressione di funzione .

Una dichiarazione di funzione definisce una variabile di funzione denominata senza richiedere l'assegnazione di variabili. Le dichiarazioni di funzione si verificano come costrutti autonomi e non possono essere nidificate all'interno di blocchi non funzionali.

function foo() {
    return 3;
}

ECMA 5 (13.0) definisce la sintassi come
identificatore di funzione (FormalParameterList opt ) {FunctionBody}

In condizioni precedenti il ​​nome della funzione è visibile nel suo ambito e nell'ambito del suo genitore (altrimenti sarebbe irraggiungibile).

E in un'espressione di funzione

Un'espressione di funzione definisce una funzione come parte di una sintassi di espressione più ampia (in genere un'assegnazione variabile). Le funzioni definite tramite espressioni di funzioni possono essere nominate o anonime. Le espressioni di funzione non devono iniziare con "funzione".

// Anonymous function expression
var a = function() {
    return 3;
}

// Named function expression
var a = function foo() {
    return 3;
}

// Self-invoking function expression
(function foo() {
    alert("hello!");
})();

ECMA 5 (13.0) definisce la sintassi come
funzione Identifier opt (FormalParameterList opt ) {FunctionBody}


16

Sto elencando le differenze di seguito:

  1. Una dichiarazione di funzione può essere posizionata ovunque nel codice. Anche se viene invocato prima che la definizione appaia nel codice, viene eseguita quando la dichiarazione di funzione viene impegnata nella memoria o in un modo in cui viene sollevata, prima che qualsiasi altro codice nella pagina inizi l'esecuzione.

    Dai un'occhiata alla seguente funzione:

    function outerFunction() {
        function foo() {
           return 1;
        }
        return foo();
        function foo() {
           return 2;
        }
    }
    alert(outerFunction()); // Displays 2

    Questo perché, durante l'esecuzione, sembra che: -

    function foo() {  // The first function declaration is moved to top
        return 1;
    }
    function foo() {  // The second function declaration is moved to top
        return 2;
    }
    function outerFunction() {
        return foo();
    }
    alert(outerFunction()); //So executing from top to bottom,
                            //the last foo() returns 2 which gets displayed

    Un'espressione di funzione, se non definita prima di chiamarla, genererà un errore. Inoltre, qui la definizione della funzione stessa non viene spostata in alto o impegnata nella memoria come nelle dichiarazioni delle funzioni. Ma la variabile a cui assegniamo la funzione viene sollevata e non definita viene assegnata ad essa.

    Stessa funzione usando le espressioni di funzione:

    function outerFunction() {
        var foo = function() {
           return 1;
        }
        return foo();
        var foo = function() {
           return 2;
        }
    }
    alert(outerFunction()); // Displays 1

    Questo perché durante l'esecuzione sembra che:

    function outerFunction() {
       var foo = undefined;
       var foo = undefined;
    
       foo = function() {
          return 1;
       };
       return foo ();
       foo = function() {   // This function expression is not reachable
          return 2;
       };
    }
    alert(outerFunction()); // Displays 1
  2. Non è sicuro scrivere dichiarazioni di funzioni in blocchi non funzionali come se non fossero accessibili.

    if (test) {
        function x() { doSomething(); }
    }
  3. L'espressione della funzione denominata come quella seguente potrebbe non funzionare nei browser Internet Explorer precedenti alla versione 9.

    var today = function today() {return new Date()}

1
@Arjun Qual è il problema se una domanda è stata posta anni prima? Una risposta non è solo vantaggiosa per l'OP ma potenzialmente per tutti gli utenti SO, indipendentemente da quando è stata posta la domanda. E cosa c'è di sbagliato nel rispondere a domande che hanno già una risposta accettata?
SantiBailors,

1
@Arjun hai capito che rispondere alle vecchie domande non è male. Se così fosse, SO avrebbe avuto una tale barriera. Immagina che ci sia un cambiamento nell'API (anche se non nel contesto di questa domanda) e qualcuno lo individua e fornisce una risposta con la nuova API, non dovrebbe essere consentito ?? Fino a quando, a meno che la risposta non abbia senso e non appartenga qui, verrebbe ridimensionata e rimossa automaticamente. Non devi preoccuparti di questo !!!!
Sudhansu Choudhary,

15

Se utilizzassi queste funzioni per creare oggetti, otterrai:

var objectOne = new functionOne();
console.log(objectOne.__proto__); // prints "Object {}" because constructor is an anonymous function

var objectTwo = new functionTwo();
console.log(objectTwo.__proto__); // prints "functionTwo {}" because constructor is a named function

Non riesco a riprodurlo. console.log(objectOne.__proto__);stampa "functionOne {}" nella mia console. Qualche idea del perché questo potrebbe essere il caso?
Mike,

Non riesco a riprodurlo.
daremkd,

1
Questa è una capacità del tuo debugger (per visualizzare la "classe" dell'oggetto registrato) e la maggior parte di loro è in grado di derivare un nome anche per espressioni di funzioni anonime in questi giorni. A proposito, dovresti chiarire che non esiste alcuna differenza funzionale tra le due istanze.
Bergi,

12

Alla luce dell'argomento "Le funzioni nominate vengono visualizzate in tracce dello stack", i moderni motori JavaScript sono in realtà abbastanza in grado di rappresentare funzioni anonime.

Al momento della stesura di questo documento, V8, SpiderMonkey, Chakra e Nitro fanno sempre riferimento alle funzioni nominate con i loro nomi. Quasi sempre si riferiscono a una funzione anonima dal suo identificatore se ne ha una.

SpiderMonkey può capire il nome di una funzione anonima restituita da un'altra funzione. Il resto non può.

Se davvero, davvero volevi che il tuo iteratore e i callback di successo si presentassero nella traccia, potresti nominare anche quelli ...

[].forEach(function iterator() {});

Ma per la maggior parte non vale la pena sottolineare.

Pettorina ( violino )

'use strict';

var a = function () {
    throw new Error();
},
    b = function b() {
        throw new Error();
    },
    c = function d() {
        throw new Error();
    },
    e = {
        f: a,
        g: b,
        h: c,
        i: function () {
            throw new Error();
        },
        j: function j() {
            throw new Error();
        },
        k: function l() {
            throw new Error();
        }
    },
    m = (function () {
        return function () {
            throw new Error();
        };
    }()),
    n = (function () {
        return function n() {
            throw new Error();
        };
    }()),
    o = (function () {
        return function p() {
            throw new Error();
        };
    }());

console.log([a, b, c].concat(Object.keys(e).reduce(function (values, key) {
    return values.concat(e[key]);
}, [])).concat([m, n, o]).reduce(function (logs, func) {

    try {
        func();
    } catch (error) {
        return logs.concat('func.name: ' + func.name + '\n' +
                           'Trace:\n' +
                           error.stack);
        // Need to manually log the error object in Nitro.
    }

}, []).join('\n\n'));

V8

func.name: 
Trace:
Error
    at a (http://localhost:8000/test.js:4:11)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: b
Trace:
Error
    at b (http://localhost:8000/test.js:7:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: d
Trace:
Error
    at d (http://localhost:8000/test.js:10:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at a (http://localhost:8000/test.js:4:11)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: b
Trace:
Error
    at b (http://localhost:8000/test.js:7:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: d
Trace:
Error
    at d (http://localhost:8000/test.js:10:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at e.i (http://localhost:8000/test.js:17:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: j
Trace:
Error
    at j (http://localhost:8000/test.js:20:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: l
Trace:
Error
    at l (http://localhost:8000/test.js:23:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at http://localhost:8000/test.js:28:19
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: n
Trace:
Error
    at n (http://localhost:8000/test.js:33:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: p
Trace:
Error
    at p (http://localhost:8000/test.js:38:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27 test.js:42

Ragno scimmia

func.name: 
Trace:
a@http://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: b
Trace:
b@http://localhost:8000/test.js:7:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: d
Trace:
d@http://localhost:8000/test.js:10:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
a@http://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: b
Trace:
b@http://localhost:8000/test.js:7:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: d
Trace:
d@http://localhost:8000/test.js:10:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
e.i@http://localhost:8000/test.js:17:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: j
Trace:
j@http://localhost:8000/test.js:20:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: l
Trace:
l@http://localhost:8000/test.js:23:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
m</<@http://localhost:8000/test.js:28:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: n
Trace:
n@http://localhost:8000/test.js:33:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: p
Trace:
p@http://localhost:8000/test.js:38:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1

chakra

func.name: undefined
Trace:
Error
   at a (http://localhost:8000/test.js:4:5)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at b (http://localhost:8000/test.js:7:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at d (http://localhost:8000/test.js:10:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at a (http://localhost:8000/test.js:4:5)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at b (http://localhost:8000/test.js:7:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at d (http://localhost:8000/test.js:10:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at e.i (http://localhost:8000/test.js:17:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at j (http://localhost:8000/test.js:20:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at l (http://localhost:8000/test.js:23:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at Anonymous function (http://localhost:8000/test.js:28:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at n (http://localhost:8000/test.js:33:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at p (http://localhost:8000/test.js:38:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)

Nitro

func.name: 
Trace:
a@http://localhost:8000/test.js:4:22
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: b
Trace:
b@http://localhost:8000/test.js:7:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: d
Trace:
d@http://localhost:8000/test.js:10:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: 
Trace:
a@http://localhost:8000/test.js:4:22
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: b
Trace:
b@http://localhost:8000/test.js:7:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: d
Trace:
d@http://localhost:8000/test.js:10:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: 
Trace:
i@http://localhost:8000/test.js:17:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: j
Trace:
j@http://localhost:8000/test.js:20:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: l
Trace:
l@http://localhost:8000/test.js:23:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: 
Trace:
http://localhost:8000/test.js:28:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: n
Trace:
n@http://localhost:8000/test.js:33:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: p
Trace:
p@http://localhost:8000/test.js:38:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

12

In JavaScript ci sono due modi per creare funzioni:

  1. Dichiarazione di funzione:

    function fn(){
      console.log("Hello");
    }
    fn();

    Questo è molto semplice, autoesplicativo, usato in molte lingue e standard in tutta la famiglia di lingue C. Abbiamo dichiarato che una funzione l'ha definita ed eseguita eseguendola chiamando.

    Quello che dovresti sapere è che le funzioni sono in realtà oggetti in JavaScript; internamente abbiamo creato un oggetto per la funzione precedente e gli abbiamo dato un nome chiamato fn o il riferimento all'oggetto è memorizzato in fn. Le funzioni sono oggetti in JavaScript; un'istanza di funzione è in realtà un'istanza di oggetto.

  2. Espressione di funzione:

    var fn=function(){
      console.log("Hello");
    }
    fn();

    JavaScript ha funzioni di prima classe, vale a dire creare una funzione e assegnarla a una variabile proprio come si crea una stringa o un numero e assegnarla a una variabile. Qui, la variabile fn è assegnata a una funzione. Il motivo di questo concetto è che le funzioni sono oggetti in JavaScript; fn punta all'istanza dell'oggetto della funzione precedente. Abbiamo inizializzato una funzione e assegnata a una variabile. Non sta eseguendo la funzione e assegnando il risultato.

Riferimento: sintassi della dichiarazione di funzione JavaScript: var fn = function () {} vs function fn () {}


1
che dire della terza opzione var fn = function fn() {...}?
Chharvey,

Ciao Chharvey, non sono sicuro della tua domanda, credo che tu stia parlando dell'espressione della funzione che ho già menzionato. Tuttavia, se c'è ancora un po 'di confusione, sii più elaborato.
Anoop Rai,

Sì, stavo chiedendo un'espressione di funzione con nome . è simile all'opzione 2, tranne per il fatto che la funzione ha un identificatore. di solito questo identificatore è uguale alla variabile a cui è assegnato, ma non è sempre così.
Chharvey,

1
Sì L'espressione della funzione denominata è simile alla mia opzione n. 2. Ben avere un identificatore non è obbligatorio in quanto non viene utilizzato. Ogni volta che eseguirai l'espressione della funzione, utilizzerai la variabile che contiene l'oggetto funzione. L'identificatore non serve a nulla.
Anoop Rai,

11

Entrambi sono modi diversi di definire una funzione. La differenza sta nel modo in cui il browser li interpreta e li carica in un contesto di esecuzione.

Il primo caso riguarda le espressioni di funzioni che si caricano solo quando l'interprete raggiunge quella riga di codice. Quindi, se lo fai come segue, visualizzerai un errore che la funzione One non è una funzione .

functionOne();
var functionOne = function() {
    // Some code
};

Il motivo è che sulla prima riga nessun valore è assegnato a functionOne, e quindi non è definito. Stiamo provando a chiamarlo come una funzione, e quindi stiamo ricevendo un errore.

Sulla seconda riga stiamo assegnando il riferimento di una funzione anonima a functionOne.

Il secondo caso riguarda le dichiarazioni di funzioni che vengono caricate prima dell'esecuzione di qualsiasi codice. Quindi, se ti piace quanto segue, non otterrai alcun errore mentre la dichiarazione viene caricata prima dell'esecuzione del codice.

functionOne();
function functionOne() {
   // Some code
}

11

A proposito di prestazioni:

Le nuove versioni di hanno V8introdotto diverse ottimizzazioni nascoste e così pure SpiderMonkey.

Non c'è quasi differenza adesso tra espressione e dichiarazione.
L'espressione della funzione sembra essere più veloce ora.

Chrome 62.0.3202 Test di Chrome

FireFox 55 Test di Firefox

Chrome Canary 63.0.3225 Test di Chrome Canary


Anonymousle espressioni di funzione sembrano avere prestazioni migliori rispetto Namedall'espressione di funzione.


Firefox Chrome Canary ChromeFirefox named_anonymous Canarino di Chrome chiamato_anonimo Chrome named_anonymous


1
Sì, questa differenza è così insignificante che si spera che gli sviluppatori si occupino di quale approccio è più sostenibile per le loro esigenze specifiche piuttosto che quale potrebbe essere più veloce (otterrai risultati jsperf diversi ad ogni tentativo a seconda di ciò che il browser sta facendo - la maggior parte delle attività javascript non deve occuparsi di micro-ottimizzazioni a questo livello).
Squidbe,

@squidbe Non c'è differenza. Guarda qui: jsperf.com/empty-tests-performance
Jack Giffin,

10

Sono abbastanza simili con alcune piccole differenze, la prima è una variabile assegnata a una funzione anonima (Dichiarazione di funzione) e la seconda è il modo normale di creare una funzione in JavaScript (Dichiarazione di funzione anonima), entrambe hanno utilizzo, contro e pro :

1. Espressione di funzione

var functionOne = function() {
    // Some code
};

Un'espressione di funzione definisce una funzione come parte di una sintassi di espressione più ampia (in genere un'assegnazione variabile). Le funzioni definite tramite Funzioni Le espressioni possono essere nominate o anonime. Le espressioni di funzione non devono iniziare con "funzione" (quindi le parentesi attorno all'esempio auto-invocante di seguito).

Assegnare una variabile a una funzione, significa che nessun sollevamento, come sappiamo le funzioni in JavaScript possono sollevare, significa che possono essere chiamate prima che vengano dichiarate, mentre le variabili devono essere dichiarate prima di accedervi, quindi in questo caso non possiamo accedi alla funzione prima di dove è stata dichiarata, inoltre potrebbe essere un modo per scrivere le tue funzioni, per le funzioni che restituiscono un'altra funzione, questo tipo di dichiarazione potrebbe avere senso, anche in ECMA6 e sopra puoi assegnarlo a una funzione freccia che può essere usato per chiamare funzioni anonime, anche questo modo di dichiarare è un modo migliore per creare funzioni di costruzione in JavaScript.

2. Dichiarazione di funzione

function functionTwo() {
    // Some code
}

Una Dichiarazione di funzione definisce una variabile di funzione denominata senza richiedere l'assegnazione di variabili. Le dichiarazioni di funzione si presentano come costrutti autonomi e non possono essere nidificate all'interno di blocchi non funzionali. È utile pensarli come fratelli di dichiarazioni variabili. Proprio come le dichiarazioni di variabili devono iniziare con "var", le dichiarazioni di funzione devono iniziare con "funzione".

Questo è il modo normale di chiamare una funzione in JavaScript, questa funzione può essere chiamata prima ancora di dichiararla come in JavaScript tutte le funzioni vengono issate, ma se hai 'usa rigoroso' questo non si solleverà come previsto, è un buon modo chiamare tutte le normali funzioni che non sono grandi nelle linee e che non sono nemmeno una funzione di costruzione.

Inoltre, se hai bisogno di maggiori informazioni su come funziona il sollevamento in JavaScript, visita il link seguente:

https://developer.mozilla.org/en-US/docs/Glossary/Hoisting


1
...also this way of declaring is a better way to create Constructor functions in JavaScript, per favore, ti prego, sono curioso!
Karl Morrison,

Uno dei motivi è perché tutte le funzioni integrate del costruttore in JavaScript create come questa funzione Number () {[codice nativo]} e non dovresti essere confuso con quelle integrate, anche in questo caso fare riferimento in un secondo momento è più sicuro e finisci codice più ordinato ma non usando il sollevamento ...
Alireza,

8

Questi sono solo due modi possibili per dichiarare le funzioni e, nel secondo modo, è possibile utilizzare la funzione prima della dichiarazione.


7

new Function()può essere usato per passare il corpo della funzione in una stringa. E quindi questo può essere usato per creare funzioni dinamiche. Passando anche lo script senza eseguire lo script.

var func = new Function("x", "y", "return x*y;");
function secondFunction(){
   var result;
   result = func(10,20);
   console.log ( result );
}

secondFunction()

Mentre questo è buono e vero, come si collega esattamente al quesiton?
Jack Giffin,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.