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

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

Lo sviluppatore precedente utilizza due metodi per dichiarare le funzioni e non riesco a capire se c’è una ragione dietro o no.

I due modi sono:

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

Quali sono le ragioni 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?

La differenza è che functionOne è un’espressione di funzione e quindi viene definita solo quando viene raggiunta tale riga, mentre functionTwo è una dichiarazione di funzione e viene definita non appena viene eseguita la funzione o lo script circostante (a causa dell’innalzamento ).

Ad esempio, un’espressione di funzione:

 // TypeError: functionOne is not a function functionOne(); var functionOne = function() { console.log("Hello!"); }; 

Per prima cosa voglio correggere Greg: function abc(){} anche un ambito – il nome abc è definito nello scope in cui si trova questa definizione. Esempio:

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

In secondo luogo, è ansible combinare entrambi gli stili:

 var xyz = function abc(){}; 

xyz sarà definito come al solito, abc non è definito in tutti i browser, ma Internet Explorer – non fare affidamento sulla sua definizione. 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 eseguire l’alias delle funzioni su tutti i browser, utilizzare questo tipo di dichiarazione:

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

In questo caso, sia xyz che abc sono alias dello stesso object:

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

Un motivo valido 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 è automaticamente assegnato. Ma quando lo definisci

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

il suo nome è vuoto: abbiamo creato una funzione anonima e l’abbiamo assegnata ad alcune variabili.

Un altro buon motivo per utilizzare lo stile combinato è utilizzare un nome interno breve per riferirsi a se stesso, fornendo al contempo 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 per riferirsi a se stesso è usare arguments.callee , che è ancora relativamente lungo, e non supportato in modalità rigorosa.)

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

 function abc(){} 

abc qui è definito ovunque nell’ambito corrente:

 // We can call it here abc(); // Works // Yet, it is defined down there. function abc(){} // We can call it again abc(); // Works 

Inoltre, è stato issato attraverso una dichiarazione di return :

 // 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 rispetto all’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 di “espressione di funzione” perché in questo modo posso controllare la visibilità. Quando definisco la funzione mi piace

 var abc = function(){}; 

So che ho definito la funzione localmente. Quando definisco la funzione mi piace

 abc = function(){}; 

So che l’ho definito a livello globale, purché non definissi abc ovunque nella catena degli ambiti. Questo stile di definizione è resiliente anche quando viene usato all’interno di eval() . Mentre la definizione

 function abc(){}; 

dipende dal contesto e potrebbe lasciarti indovinare dove è effettivamente definito, specialmente nel caso di eval() – la risposta è: Dipende dal browser.

Ecco il resoconto sui moduli standard che creano le funzioni: (Originariamente scritto per un’altra domanda, ma adattato dopo essere stato spostato nella domanda canonica).

Condizioni:

  • ES5 : ECMAScript 5th edition , 2009
  • ES2015 : ECMAScript 2015 (noto anche come “ES6”)

La lista veloce:

  • Dichiarazione delle funzioni

  • function “anonima” Espressione (che a dispetto del termine, a volte crea funzioni con nomi)

  • function denominata espressione

  • Accessor Function Initializer (ES5 +)

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

  • Dichiarazione del metodo in Initializer object (ES2015 +)

  • Costruttore e dichiarazioni dei metodi in class (ES2015 +)

Dichiarazione delle funzioni

La prima forma è una dichiarazione di funzione , che assomiglia a questa:

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

Una dichiarazione di funzione è una dichiarazione ; non è una dichiarazione o un’espressione. In quanto tale, non lo segui con a ; (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 creata viene assegnato un nome proprio ( x nell’esempio sopra) e tale nome viene inserito nell’ambito in cui appare la dichiarazione.

Poiché viene elaborato prima di qualsiasi codice passo a passo nello stesso contesto, puoi fare cose come questa:

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

Fino alla versione ES2015, le specifiche non riguardavano ciò che un motore JavaScript dovrebbe fare se si inserisce 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 dal momento che vengono elaborati prima di eseguire il codice passo-passo, è difficile sapere cosa fare quando si trovano in una struttura di controllo.

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

A partire da ES2015, le specifiche dicono cosa fare. In realtà, ci sono tre cose 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à libere sono complicate, ma in modalità rigorosa , le dichiarazioni di funzione nei blocchi sono semplici: sono locali al blocco (hanno un ambito di blocco , che è anche nuovo in ES2015) e vengono issate in cima 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) 

Espressione della function "anonima"

La seconda forma comune è chiamata espressione di funzione anonima :

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

Come tutte le espressioni, viene valutato quando viene raggiunto nell'esecuzione passo passo del codice.

In ES5, la funzione creata non ha nome (è anonimo). In ES2015, alla funzione viene assegnato un nome, se ansible, deducendolo dal contesto. Nell'esempio sopra, il nome sarebbe y . Qualcosa di simile è fatto quando la funzione è il valore di un inizializzatore di proprietà. (Per i dettagli su quando ciò accade e le regole, cerca SetFunctionName nella specifica - appare dappertutto .)

function denominata espressione

Il terzo modulo è un'espressione di funzione con nome ("NFE"):

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

La funzione che crea ha un nome proprio ( w in 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 è compreso nell'ambito della funzione stessa:

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

Nota che le NFE sono state spesso fonte di bug per le implementazioni di JavaScript. IE8 e precedenti, ad esempio, gestiscono le NFE in modo completamente errato , creando due diverse funzioni in due momentjs diversi. Le prime versioni di Safari presentavano anche problemi. La buona notizia è che le versioni correnti dei browser (IE9 e versioni successive, Safari corrente) non presentano più tali problemi. (Ma al momento della stesura di questo articolo, purtroppo, IE8 rimane in uso diffuso, e quindi usare NFE con il codice per il web in generale è ancora problematico.)

Accessor Function Initializer (ES5 +)

A volte le funzioni possono entrare di nascosto in gran parte inosservate; questo è il caso con le funzioni accessorie . 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" 

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

È anche ansible creare funzioni di Object.defineProperty con Object.defineProperty , Object.defineProperties e il secondo argomento meno noto di Object.create .

Arrow Function Expression (ES2015 +)

ES2015 ci porta 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 che n => n * 2 cosa si nasconde nella chiamata a map() ? Questa è una funzione.

Un paio di cose sulle funzioni della freccia:

  1. Non hanno il loro this . Invece, si chiudono su this del contesto in cui sono definiti. (Si chiudono anche su arguments e, se del caso, super .) Ciò significa che this al loro interno è lo stesso di quello in cui sono stati creati e non può essere modificato.

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

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

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

(Ricorda che la Array#map passa la voce come primo argomento e l'indice come seconda.)

In entrambi i casi, il corpo della funzione è solo un'espressione; il valore di ritorno della funzione sarà automaticamente il risultato di tale espressione (non si utilizza un return esplicito).

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

 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 { ... } è chiamata una funzione di freccia con un corpo di espressione o corpo conciso . (Inoltre: una funzione di freccia concisa .) Quello con { ... } definisce il corpo è una funzione di freccia con un corpo di funzione . (Inoltre: una funzione di freccia dettagliata ).

Dichiarazione del metodo in Initializer object (ES2015 +)

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

 var o = { foo() { } }; 

l'equivalente in ES5 e precedenti sarebbe:

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

Costruttore e dichiarazioni dei metodi in class (ES2015 +)

ES2015 ci offre la syntax della class , inclusi i costruttori e i metodi dichiarati:

 class Person { constructor(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; } getFullName() { return this.firstName + " " + this.lastName; } } 

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

Parlando del contesto globale, sia l’istruzione var che una FunctionDeclaration alla fine creeranno una proprietà non cancellabile sull’object globale, ma il valore di entrambi può essere sovrascritto .

La sottile differenza tra i due modi è che quando il processo di istanziazione delle variabili viene eseguito (prima dell’esecuzione effettiva del codice) tutti gli identificatori dichiarati con var verranno inizializzati con undefined e quelli utilizzati dalle dichiarazioni di FunctionDeclaration saranno disponibili da quel momento, per esempio:

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

L’assegnazione della bar FunctionExpression avviene fino al runtime.

Una proprietà globale creata da una FunctionDeclaration può 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 il secondo ce l’ha, che può essere davvero utile quando si esegue il debug (cioè ispezionando uno stack di chiamate).

Informazioni sul tuo primo esempio modificato ( foo = function() { alert('hello!'); }; ), È un compito non dichiarato, ti incoraggio caldamente a usare sempre la parola chiave var .

Con un’assegnazione, senza l’istruzione var , se l’identificatore di riferimento non viene trovato nella catena dell’ambito, diventerà una proprietà eliminabile dell’object globale.

Inoltre, le assegnazioni non dichiarate generano un ReferenceError su ECMAScript 5 in modalità Strict .

A deve leggere:

  • Espressioni di funzioni con nome demistificate

Nota : questa risposta è stata unita da un’altra domanda , in cui il maggior dubbio e l’idea errata dell’OP erano che gli identificatori dichiarati con una FunctionDeclaration non potevano essere sovrascritti, il che non è il caso.

I due frammenti di codice che hai pubblicato in questa sezione, per quasi tutti gli scopi, si comportano allo stesso modo.

Tuttavia, la differenza di comportamento è che con la prima variante ( var functionOne = function() {} ), tale 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 è assegnata alla variabile foo in fase di esecuzione. Nel secondo, la funzione è assegnata a foo , foo , in fase di analisi.

Altre informazioni tecniche

JavaScript ha tre modi per definire le funzioni.

  1. Il tuo primo snippet mostra un’espressione di funzione . Ciò comporta l’utilizzo dell’operatore “funzione” per creare una funzione – il risultato di tale operatore può essere memorizzato in qualsiasi variabile o proprietà dell’object. L’espressione della funzione è potente in questo modo. L’espressione di funzione è spesso chiamata “funzione anonima”, perché non deve avere un nome,
  2. Il tuo secondo esempio è una dichiarazione di funzione . Questo usa l’ istruzione “function” per creare una funzione. La funzione è resa disponibile in fase di analisi e può essere richiamata ovunque in tale ambito. Puoi ancora memorizzarlo in una proprietà variabile o object in seguito.
  3. Il terzo modo di definire una funzione è il costruttore “Funzione ()” , che non è mostrato nel tuo post originale. Non è consigliabile utilizzarlo poiché funziona allo stesso modo di eval() , che ha i suoi problemi.

Una spiegazione migliore alla risposta di Greg

 functionTwo(); function functionTwo() { } 

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

Perché:

Le dichiarazioni delle funzioni e le dichiarazioni delle variabili vengono sempre spostate ( hoisted ) in modo invisibile nella parte superiore del loro ambito di contenimento dall’interprete JavaScript. Parametri di funzione e nomi definiti dalla lingua sono, ovviamente, già lì. ben ciliegio

Ciò significa che il codice come questo:

 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. Solo il nome è issato.

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

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

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

Io spesso costruisco moduli JavaScript con uno schema come questo:

 (function(){ var exports = {}; function privateUtil() { ... } exports.publicUtil = function() { ... }; return exports; })(); 

Con questo modello, le tue funzioni pubbliche useranno tutte le assegnazioni, mentre le tue funzioni private usano la dichiarazione.

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

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 myfunction sovrascriverà qualsiasi definizione precedente, poiché verrà eseguita in fase di analisi.

Mentre

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

fa il lavoro corretto di definire la myfunction solo quando la condition è soddisfatta.

Un motivo importante è aggiungere una sola variabile come “Root” del tuo spazio dei nomi …

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

o

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

Esistono molte tecniche per il namespace. È diventato più importante con la pletora di moduli JavaScript disponibili.

Vedi anche Come dichiarare un namespace in JavaScript?

Il sollevamento è l’azione dell’interprete JavaScript che sposta tutte le dichiarazioni di variabili e funzioni all’inizio dell’ambito corrente.

Tuttavia, vengono issate solo le dichiarazioni effettive. lasciando i compiti 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 scope locale. significa che sono disponibili / accessibili all’interno del corpo della funzione (scope), non sono disponibili al di fuori del corpo della funzione.

Variabile

Javascript è chiamato linguaggio vagamente typescript. Ciò significa che le variabili Javascript possono contenere il valore di qualsiasi tipo di dati . Javascript si occupa automaticamente della modifica del 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 sono issate in cima alla pagina con accesso globale.
  • le funzioni dichiarate all’interno del blocco funzione vengono issate in cima al blocco.
  • Il valore di ritorno predefinito della funzione è ‘ indefinito ‘, il valore predefinito della dichiarazione Variabile anche ‘indefinito’

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

Dichiarazione delle funzioni

 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(); 

È ansible controllare la dichiarazione di funzione, il 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 class, quindi essendo un object, è ansible 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 di funzione di freccia ha una syntax più breve, sono più adatti per le funzioni non di metodo e non possono essere utilizzati come costruttori.

ArrowFunction : ArrowParameters => ConciseBody .

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

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

Mi sono chiesto quale sia il modo migliore per molto tempo ora, e grazie a http://jsperf.com ora lo so 🙂

inserisci la descrizione dell'immagine qui

Le dichiarazioni di funzione sono più veloci, ed è quello che conta davvero nel web dev giusto? 😉

A function declaration and a function expression assigned to a variable behave the same once the binding is established.

There is a difference however at how and when the function object is actually associated with its variable. This difference is due to the mechanism called variable hoisting in JavaScript.

Basically, all function declarations and variable declarations are hoisted to the top of the function in which the declaration occurs (this is why we say that JavaScript has function scope ).

  • When a function declaration is hoisted, the function body “follows” so when the function body is evaluated, the variable will immediately be bound to a function object.

  • When a variable declaration is hoisted, the initialization does not follow, but is “left behind”. The variable is initialized to undefined at the start of the function body, and will be assigned a value at its original location in the code. (Actually, it will be assigned a value at every location where a declaration of a variable with the same name occurs.)

The order of hoisting is also important: function declarations take precedence over variable declarations with the same name, and the last function declaration takes precedence over previous function declarations with the same name.

Some examples…

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

Variable foo is hoisted to the top of the function, initialized to undefined , so that !foo is true , so foo is assigned 10 . The foo outside of bar ‘s scope plays no role and is untouched.

 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 

Function declarations take precedence over variable declarations, and the last function declaration “sticks”.

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

In this example a is initialized with the function object resulting from evaluating the second function declaration, and then is assigned 4 .

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

Here the function declaration is hoisted first, declaring and initializing variable a . Next, this variable is assigned 10 . In other words: the assignment does not assign to outer variable a .

The first example is a function declaration:

 function abc(){} 

The second example is a function expression:

 var abc = function() {}; 

The main difference is how they are hoisted (lifted and declared). In the first example, the whole function declaration is hoisted. In the second example only the var ‘abc’ is hoisted, its value (the function) will be undefined, and the function itself remains at the position that it is declared.

To put it simply:

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

To study more about this topic I strongly recommend you this link

In terms of code maintenance cost, named functions are more preferable:

  • Independent from the place where they are declared (but still limited by scope).
  • More resistant to mistakes like conditional initialization (you are still able to override if wanted to).
  • The code becomes more readable by allocating local functions separately of scope functionality. Usually in the scope the functionality goes first, followed by declarations of local functions.
  • In a debugger you will clearly see the function name on the call stack instead of an “anonymous/evaluated” function.

I suspect more PROS for named functions are follow. And what is listed as an advantage of named functions is a disadvantage for anonymous ones.

Historically, anonymous functions appeared from the inability of JavaScript as a language to list members with named functions:

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

I use the variable approach in my code for a very specific reason, the theory of which has been covered in an abstract way above, but an example might help some people like me, with limited JavaScript expertise.

I have code that I need to run with 160 independently-designed brandings. Most of the code is in shared files, but branding-specific stuff is in a separate file, one for each branding.

Some brandings require specific functions, and some do not. Sometimes I have to add new functions to do new branding-specific things. I am happy to change the shared coded, but I don’t want to have to change all 160 sets of branding files.

By using the variable syntax, I can declare the variable (a function pointer essentially) in the shared code and either assign a trivial stub function, or set to null.

The one or two brandings that need a specific implementation of the function can then define their version of the function and assign this to the variable if they want, and the rest do nothing. I can test for a null function before I execute it in the shared code.

From people’s comments above, I gather it may be possible to redefine a static function too, but I think the variable solution is nice and clear.

In computer science terms, we talk about anonymous functions and named functions. I think the most important difference is that an anonymous function is not bound to an name, hence the name anonymous function. In JavaScript it is a first class object dynamically declared at runtime.

For more information on anonymous functions and lambda calculus, Wikipedia is a good start ( http://en.wikipedia.org/wiki/Anonymous_function ).

Greg’s Answer is good enough, but I still would like to add something to it that I learned just now watching Douglas Crockford’s videos.

Function expression:

 var foo = function foo() {}; 

Function statement:

 function foo() {}; 

The function statement is just a shorthand for var statement with a function value.

Così

 function foo() {}; 

expands to

 var foo = function foo() {}; 

Which expands further to:

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

And they are both hoisted to the top of the code.

Screenshot from video

@EugeneLazutkin gives an example where he names an assigned function to be able to use shortcut() as an internal reference to itself. John Resig gives another example – copying a recursive function assigned to another object in his Learning Advanced Javascript tutorial. While assigning functions to properties isn’t strictly the question here, I recommend actively trying the tutorial out – run the code by clicking the button in the upper right corner, and double click the code to edit to your liking.

Examples from the tutorial: recursive calls in yell() :

Tests fail when the original ninja object is removed. (page 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?" ); } 

If you name the function that will be called recursively, the tests will pass. (page 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." ); 

Another difference that is not mentioned in the other answers is that if you use the anonymous function

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

and use that as a constructor as in

 var one = new functionOne(); 

then one.constructor.name will not be defined. Function.name is non-standard but is supported by Firefox, Chrome, other Webkit-derived browsers and IE 9+.

With

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

it is possible to retrieve the name of the constructor as a string with two.constructor.name .

If you would use those functions to create objects, you would get:

 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 

I’m listing out the differences below:

  1. A function declaration can be placed anywhere in the code. Even if it is invoked before the definition appears in code, it gets executed as function declaration is committed to memory or in a way it is hoisted up, before any other code in the page starts execution.

    Take a look at the function below:

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

    This is because, during execution, it looks like:-

     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 

    A function expression, if not defined before calling it, will result in an error. Also, here the function definition itself is not moved to the top or committed to memory like in the function declarations. But the variable to which we assign the function gets hoisted up and undefined gets assigned to it.

    Same function using function expressions:

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

    This is because during execution, it looks like:

     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. It is not safe to write function declarations in non-function blocks like if because they won’t be accessible.

     if (test) { function x() { doSomething(); } } 
  3. Named function expression like the one below, may not work in Internet Explorer browsers prior to version 9.

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

The first one (function doSomething(x)) should be part of an object notation.

The second one ( var doSomething = function(x){ alert(x);} ) is simply creating an anonymous function and assigning it to a variable, doSomething . So doSomething() will call the function.

You may want to know what a function declaration and function expression is.

A function declaration defines a named function variable without requiring variable assignment. Function declarations occur as standalone constructs and cannot be nested within non-function blocks.

 function foo() { return 3; } 

ECMA 5 (13.0) defines the syntax as
function Identifier ( FormalParameterList opt ) { FunctionBody }

In above condition the function name is visible within its scope and the scope of its parent (otherwise it would be unreachable).

And in a function expression

A function expression defines a function as a part of a larger expression syntax (typically a variable assignment ). Functions defined via functions expressions can be named or anonymous. Function expressions should not start with “function”.

 // 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) defines the syntax as
function Identifier opt ( FormalParameterList opt ) { FunctionBody }

In light of the “named functions show up in stack traces” argument, modern JavaScript engines are actually quite capable of representing anonymous functions.

As of this writing, V8, SpiderMonkey, Chakra and Nitro always refer to named functions by their names. They almost always refer to an anonymous function by its identifier if it has one.

SpiderMonkey can figure out the name of an anonymous function returned from another function. The rest can’t.

If you really, really wanted your iterator and success callbacks to show up in the trace, you could name those too…

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

But for the most part it’s not worth stressing over.

Harness ( Fiddle )

 '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 ei (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 

SpiderMonkey

 func.name: Trace: [email protected]://localhost:8000/test.js:4:5 @http://localhost:8000/test.js:47:9 @http://localhost:8000/test.js:54:1 func.name: b Trace: [email protected]://localhost:8000/test.js:7:9 @http://localhost:8000/test.js:47:9 @http://localhost:8000/test.js:54:1 func.name: d Trace: [email protected]://localhost:8000/test.js:10:9 @http://localhost:8000/test.js:47:9 @http://localhost:8000/test.js:54:1 func.name: Trace: [email protected]://localhost:8000/test.js:4:5 @http://localhost:8000/test.js:47:9 @http://localhost:8000/test.js:54:1 func.name: b Trace: [email protected]://localhost:8000/test.js:7:9 @http://localhost:8000/test.js:47:9 @http://localhost:8000/test.js:54:1 func.name: d Trace: [email protected]://localhost:8000/test.js:10:9 @http://localhost:8000/test.js:47:9 @http://localhost:8000/test.js:54:1 func.name: Trace: [email protected]://localhost:8000/test.js:17:13 @http://localhost:8000/test.js:47:9 @http://localhost:8000/test.js:54:1 func.name: j Trace: [email protected]://localhost:8000/test.js:20:13 @http://localhost:8000/test.js:47:9 @http://localhost:8000/test.js:54:1 func.name: l Trace: [email protected]://localhost:8000/test.js:23:13 @http://localhost:8000/test.js:47:9 @http://localhost:8000/test.js:54:1 func.name: Trace: m 

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 ei (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: [email protected]://localhost:8000/test.js:4:22 http://localhost:8000/test.js:47:13 [email protected][native code] global [email protected]://localhost:8000/test.js:44:33 func.name: b Trace: [email protected]://localhost:8000/test.js:7:26 http://localhost:8000/test.js:47:13 [email protected][native code] global [email protected]://localhost:8000/test.js:44:33 func.name: d Trace: [email protected]://localhost:8000/test.js:10:26 http://localhost:8000/test.js:47:13 [email protected][native code] global [email protected]://localhost:8000/test.js:44:33 func.name: Trace: [email protected]://localhost:8000/test.js:4:22 http://localhost:8000/test.js:47:13 [email protected][native code] global [email protected]://localhost:8000/test.js:44:33 func.name: b Trace: [email protected]://localhost:8000/test.js:7:26 http://localhost:8000/test.js:47:13 [email protected][native code] global [email protected]://localhost:8000/test.js:44:33 func.name: d Trace: [email protected]://localhost:8000/test.js:10:26 http://localhost:8000/test.js:47:13 [email protected][native code] global [email protected]://localhost:8000/test.js:44:33 func.name: Trace: [email protected]://localhost:8000/test.js:17:30 http://localhost:8000/test.js:47:13 [email protected][native code] global [email protected]://localhost:8000/test.js:44:33 func.name: j Trace: [email protected]://localhost:8000/test.js:20:30 http://localhost:8000/test.js:47:13 [email protected][native code] global [email protected]://localhost:8000/test.js:44:33 func.name: l Trace: [email protected]://localhost:8000/test.js:23:30 http://localhost:8000/test.js:47:13 [email protected][native code] global [email protected]://localhost:8000/test.js:44:33 func.name: Trace: http://localhost:8000/test.js:28:30 http://localhost:8000/test.js:47:13 [email protected][native code] global [email protected]://localhost:8000/test.js:44:33 func.name: n Trace: [email protected]://localhost:8000/test.js:33:30 http://localhost:8000/test.js:47:13 [email protected][native code] global [email protected]://localhost:8000/test.js:44:33 func.name: p Trace: [email protected]://localhost:8000/test.js:38:30 http://localhost:8000/test.js:47:13 [email protected][native code] global [email protected]://localhost:8000/test.js:44:33 

In JavaScript there are two ways to create functions:

  1. Function declaration:

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

    This is very basic, self-explanatory, used in many languages and standard across C family of languages. We declared a function defined it and executed it by calling it.

    What you should be knowing is that functions are actually objects in JavaScript; internally we have created an object for above function and given it a name called fn or the reference to the object is stored in fn. Functions are objects in JavaScript; an instance of function is actually an object instance.

  2. Function expression:

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

    JavaScript has first-class functions, that is, create a function and assign it to a variable just like you create a string or number and assign it to a variable. Here, the fn variable is assigned to a function. The reason for this concept is functions are objects in JavaScript; fn is pointing to the object instance of the above function. We have initialized a function and assigned it to a variable. It’s not executing the function and assigning the result.

Reference: JavaScript function declaration syntax: var fn = function() {} vs function fn() {}

Both are different ways of defining a function. The difference is how the browser interprets and loads them into an execution context.

The first case is of function expressions which loads only when the interpreter reaches that line of code. So if you do it like the following, you will get an error that the functionOne is not a function .

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

The reason is that on the first line no value is assigned to functionOne, and hence it is undefined. We are trying to call it as a function, and hence we are getting an error.

On the second line we are assigning the reference of an anonymous function to functionOne.

The second case is of function declarations that loads before any code is executed. So if you do like the following you won’t get any error as the declaration loads before code execution.

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

About performance:

New versions of V8 introduced several under-the-hood optimizations and so did SpiderMonkey .

There is almost no difference now between expression and declaration.
Function expression appears to be faster now.

Chrome 62.0.3202 Chrome test

FireFox 55 Firefox test

Chrome Canary 63.0.3225 Chrome Canary test

Anonymous function expressions appear to have better performance against Named function expression.

Firefox Firefox named_anonymous Chrome Canary Chrome canary named_anonymous Chrome Chrome named_anonymous

There are three noteworthy comparisons between the two different declarations of functions as listed below.

  1. Availability (scope) of the function

The following works because function add() is scoped to the nearest block:

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

They are pretty similar with some small differences, first one is a variable which assigned to an anonymous function (Function Declaration) and second one is the normal way to create a function in JavaScript(Anonymous function Declaration), both has usage, cons and pros:

1. Function Expression

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

A Function Expression defines a function as a part of a larger expression syntax (typically a variable assignment ). Functions defined via Functions Expressions can be named or anonymous. Function Expressions must not start with “function” (hence the parentheses around the self invoking example below).

Assign a variable to a function, means no Hoisting, as we know functions in JavaScript can Hoist, means they can be called before they get declared, while variables need to be declared before getting access to them, so means in this case we can not access the function before where it’s declared, also it could be a way that you write your functions, for the functions which return another function, this kind of declaration could make sense, also in ECMA6 & above you can assign this to an arrow function which can be used to call anonymous functions, also this way of declaring is a better way to create Constructor functions in JavaScript.

2. Function Declaration

 function functionTwo() { // Some code } 

A Function Declaration defines a named function variable without requiring variable assignment. Function Declarations occur as standalone constructs and cannot be nested within non-function blocks. It’s helpful to think of them as siblings of Variable Declarations. Just as Variable Declarations must start with “var”, Function Declarations must begin with “function”.

This is the normal way of calling a function in JavaScript, this function can be called before you even declare it as in JavaScript all functions get Hoisted, but if you have ‘use strict’ this won’t Hoist as expected, it’s a good way to call all normal functions which are not big in lines and neither are a constructor function.

Also, if you need more info about how hoisting works in JavaScript, visit the link below:

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

This is just two possible ways of declaring functions, and in the second way, you can use the function before declaration.

new Function() can be used to pass the function’s body in a string. And hence this can be used to create dynamic functions. Also passing the script without executing the script.

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