name - variable javascript function




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

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 oggetto.

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).

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?


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:

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 oggetto (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 possibile, 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 momenti 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 possibile 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 oggetto (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 sintassi 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 .


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 hoisting ).

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!");
}

Ciò significa anche che non è possibile definire condizionatamente funzioni utilizzando le dichiarazioni di funzione:

if (test) {
   // Error or misbehavior
   function functionThree() { doSomething(); }
}

Quanto sopra definisce effettivamente functionThree indipendentemente dal valore del test , a meno che non sia in vigore l' use strict , nel qual caso esso solleva semplicemente un errore.


Parlando del contesto globale, sia l'istruzione var che una FunctionDeclaration alla fine creeranno una proprietà non cancellabile sull'oggetto 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'oggetto globale.

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

A deve leggere:

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.


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 :)

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


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?


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

fornisce un esempio in cui nomina una funzione assegnata per poter essere utilizzatashortcut() come riferimento interno a se stessa. John Resig fornisce un altro esempio: copia di una funzione ricorsiva assegnata a un altro oggetto nel suo tutorial di apprendimento avanzato Javascript . Mentre assegnare le funzioni alle proprietà non è strettamente la questione 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 l'oggetto ninja originale viene rimosso. (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." );

Hoisting è 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.

Variable

Javascript è chiamato linguaggio vagamente dattiloscritto. Ciò significa che le variabili Javascript possono contenere il valore di qualsiasi tipo di Data-Type . 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 è ' undefined ', il valore predefinito della dichiarazione Variable 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();

È possibile 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 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 di funzione di freccia ha una sintassi 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

Informazioni sulle prestazioni:

Le nuove versioni V8introdussero diverse ottimizzazioni sotto il cofano e così fecero SpiderMonkey.

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

Chrome 62.0.3202

FireFox 55

Chrome Canary 63.0.3225


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


Firefox Chrome Canary Chrome


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

  1. Disponibilità (ambito) della funzione

Il seguente funziona perché function add()è collegato 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é il var add=superseed è 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;
}

Quanto segue non funziona perché addviene dichiarato dopo che è stato utilizzato.

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

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

  1. (funzione) .name

Il nome di una funzione function thefuncname(){}è thefuncname 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 è 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 delle funzioni è la stringa vuota ( "").

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

Infine, mentre la variabile a cui è assegnata la funzione inizialmente imposta 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 di compilazione JIST in microsecondi, ma alla fine il risultato è lo stesso. Per dimostrarlo, esaminiamo l'efficienza di JSPerf ai microbenchmark confrontando la velocità di due snippet di codice vuoto. I test JSPerf si trovano qui . E i test di jsben.ch sono stati trovati qui . Come puoi vedere, c'è una differenza notevole quando non dovrebbe essercene. Se sei davvero un maniaco delle prestazioni come me, allora potrebbe essere più utile tentare di ridurre il numero di variabili e funzioni nell'ambito e, soprattutto, di eliminare il polimorfismo (come l'uso della stessa variabile per memorizzare due tipi diversi).

Qual è il "blocco più vicino"

Il "blocco più vicino" è la "funzione" più vicina (incluse le funzioni asincrone, le funzioni del generatore e le funzioni del generatore asincrono). Tuttavia, è interessante function functionName() {}notare che si comporta come un var functionName = function() {}quando in un blocco non di chiusura di 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;
    }
})();


Il primo (funzione doSomething (x)) dovrebbe essere parte di una notazione di 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 che cos'è una dichiarazione di funzione e un'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 annidati all'interno di blocchi non funzionali.

function foo() {
    return 3;
}

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

Nella condizione precedente il nome della funzione è visibile all'interno del suo ambito e dell'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 di variabile). Le funzioni definite tramite espressioni di funzioni possono essere denominate o anonime. Le espressioni di funzione non dovrebbero iniziare con "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) definisce la sintassi come
funzione Identificatore opt (FormalParameterList opt ) {FunctionBody}


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 e l'ha eseguita chiamandola.

    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, cioè crea una funzione e assegnala a una variabile proprio come si crea una stringa o un numero e assegnarlo a una variabile. Qui, la variabile fn è assegnata a una funzione. La ragione di questo concetto è che le funzioni sono oggetti in JavaScript; fn sta puntando all'istanza dell'oggetto della funzione precedente. Abbiamo inizializzato una funzione e l'abbiamo assegnata a una variabile. Non sta eseguendo la funzione e assegnando il risultato.

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


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

  • Indipendenti dal luogo in cui sono dichiarati (ma ancora limitati dallo scopo).
  • Più resistente agli errori come l'inizializzazione condizionale (sei ancora in grado di eseguire l'override se lo desideri).
  • Il codice diventa più leggibile allocando le funzioni locali separatamente dalla funzionalità dell'ambito. Di solito nel campo di applicazione la funzionalità va prima, seguita dalle dichiarazioni delle funzioni locali.
  • In un debugger vedrai chiaramente il nome della funzione sullo stack delle chiamate invece di una funzione "anonima / valutata".

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

Storicamente, le funzioni anonime apparivano dall'incapacità di JavaScript come linguaggio per elencare i membri con funzioni con nome:

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

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


Se si usassero queste funzioni per creare oggetti, si otterrebbe:

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

Sto elencando le differenze di seguito:

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

    Dai un'occhiata alla funzione qui sotto:

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

    Questo perché, durante l'esecuzione, assomiglia a: -

    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, genera un errore. Inoltre, qui la definizione della funzione stessa non viene spostata in alto o impegnata in memoria come nelle dichiarazioni delle funzioni. Ma la variabile a cui assegniamo la funzione viene issata in alto e indefinita 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 di una funzione denominata come quella riportata di seguito potrebbe non funzionare nei browser di Internet Explorer precedenti alla versione 9.

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

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.nameè non 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 una stringa con two.constructor.name.


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

Ho il codice che ho bisogno di eseguire con 160 brandings progettati in modo indipendente. La maggior parte del codice è in file condivisi, ma i contenuti specifici del marchio si trovano in un file separato, uno per ciascun marchio.

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

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

L'uno o due marchi 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 provare una funzione nulla prima di eseguirla nel codice condiviso.

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


Entrambi sono diversi modi di definire una funzione. La differenza è come il browser interpreta e li carica in un contesto di esecuzione.

Il primo caso è di espressioni di funzione che vengono caricate solo quando l'interprete raggiunge quella linea di codice. Quindi, se lo fai come il seguente, riceverai un errore che functionOne non è una funzione .

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

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

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

Il secondo caso è di dichiarazioni di funzioni che vengono caricate prima dell'esecuzione di qualsiasi codice. Quindi, se ti piace il seguente, non otterrai alcun errore dato che la dichiarazione viene caricata prima dell'esecuzione del codice.

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




idioms