Funzioni

Questa traduzione è incompleta. Collabora alla traduzione di questo articolo dall’originale in lingua inglese.

Parlando in termini generici, una funzione è un "sottopogramma" che può essere chiamato da un codice esterno (o interno nel caso di ricorsione) alla funzione stessa. Come il programma stesso, una funzione è composta da una sequenza di istruzioni chiamata corpo della funzione. Ad una funzione possono essere passati valori, e la funzione restituisce un valore.

In JavaScript, le funzioni sono oggetti di prima classe, perchè sono dotate di proprietà e di metodi, proprio come qualsiasi altro oggetto. Ciò che le distingue dagli altri oggetti è la possibilità di essere chiamate ( invocate ). Le funzioni sono oggetti di tipo Function.

Per maggiori esempi e spiegazioni, vedere anche JavaScript la guida sulle funzioni.

Descrizione

Ogni funzione in JavaScript è un oggetto di tipo Function. Vedi la pagina Function for informazioni su proprietà e metodi dell'oggetto Function.

Le funzioni non sono come le procedure. Una funzione restituisce sempre un valore, mentre una procedura può anche non restituire alcun valore.

Per restituire un valore specifico differente da quello di default, una fuzione deve avere un istruzione return che specifica il valore di ritorno. Una funzione senza un istruzione di ritorno restituirà il valore di  default. Nel caso di un costruttore invocato con la parola chiave new, il valore di default è il valore del suo parametro this. Per tutte le altre funzioni, il valore di ritorno di default è undefined.

I parametri di una chiamata di funzione sono gli argomenti della funzione. Gli argomenti sono passati alla funzione per valore. Se la funzione cambia il valore di un argomento, questo cambiamento non si riflette globalmente o nella funzione chiamante. Sebbene anche i riferimenti a oggetti siano valori, essi sono speciali: se una funzione cambia le proprietà di un oggetto a cui riferisce, quel cambiamento è visibile anche al di fuori della funzione, come dimostrato nel seguente esempio:

/* Dichiarazione della funzione 'myFunc' */
function myFunc(theObject) {
   theObject.brand = "Toyota";
 }
 
 /*
  * Dichiarazione della variabile 'mycar';
  * creazione e inizializzazione di un nuovo Object;
  * associazione alla riferimento 'mycar'
  */
 var mycar = {
   brand: "Honda",
   model: "Accord",
   year: 1998
 };

 /* Logs 'Honda' */
 console.log(mycar.brand);

 /* Passaggio del riferimento dell'oggetto alla funzione */
 myFunc(mycar);

 /*
  * Logs 'Toyota' come il valore della proprietà 'brand'
  * dell'oggetto, come è stato cambiato dalla funzione.
  */
 console.log(mycar.brand);

NB: l'oggetto console non è un oggetto standard. Non usatelo in un sito web, poichè potrebbe non funzionare correttamente. Per verificare il funzionamento dell'esempio precedente, usate, piuttosto:

           window.alert(mycar.brand);

La parola chiave this non fa riferimento alla funzione attualmente in esecuzione, per questo motivo si deve far riferimento ad oggetti Function  per nome, anche quando all'interno del corpo della funzione stessa.

Definizione di funzioni

Ci sono diversi modi per definire le funzioni:

La dichiarazione di funzione (istruzione function)

C'è una speciale sintassi per la dichiarazione di funzioni (per dettagli guarda function statement):

function name([param[, param[, ... param]]]) {
   statements
}
name
Il nome della funzione
param
Il nome di un argomento da passare alla funzione. Una funzione può avere fino a 255 argomenti.
statements
Le istruzioni comprese nel corpo della funzione.

L'espressione di funzione (espressione function)

Una espressione di funzione è simile ed ha la stessa sintassi della dichiarazione di funzione (per dettagli guarda function expression):

function [name]([param] [, param] [..., param]) {
   statements
}
name
Il nome della funzione. Può essere omesso, in qual caso la funzione è nota come funzione anonima.
param
Il nome di un argomento da passare alla funzione. Una funzione può avere fino a 255 argomenti.
statements
Le istruzioni comprese nel corpo della funzione.

La dichiarazione di funzione generatrice (espressione function*)

Note: Le funzioni generatrici sono un tecnologia sperimentale, parte della proposta di specifica ECMAScript 6, e non sono ancora ampiamente supportate dai browsers.

C'è una sintassi speciale per le funzioni generatrici (per dettagli vedi function* statement ):

function* name([param[, param[, ... param]]]) {
   statements
}
name
Nome della funzione.
param
Nome dell'argomento da passare alla funzione. Una funzione può avere fino a 255 agromenti.
statements
Le istruzioni comprese nel corpo della funzione.

L'espressione di funzione generatrice (espressione function*)

Note: Le funzioni generatrici sono una tecnologia sperimentale, parte della proposta di specifica ECMAScript 6, e non sono ancora ampiamente supportamente dai browsers.

Una espressione di funzione generatrice è similare ed ha la stessa sintassi di una dichiarazione di funzione generatrice (per dettagli vedi function* expression ):

function* [name]([param] [, param] [..., param]) {
   statements
}
name
Nome della funzione. Può essere omesso, nel qual caso la funzione è nota come funzione anonima.
param
Nome dell'argomento da passare alla funzione. Una funzione può avere fino a 255 agromenti.
statements
Le istruzioni comprese nel corpo della funzione.

L'espressione di funzione a freccia (=>)

Note: L'espressione di funzione a freccia sono una tecnologia sperimentareparte della proposta di specifica ECMAScript 6, e non sono ancora ampiamente supportate dai browsers.

Un' espressione di funzione a freccia ha una sintassi ridotta e lessicalmnete associa il proprio valore this (per dettagli vedere arrow functions ):

([param] [, param]) => {
   statements
}

param => expression
param
Il nome di un parametro. È necessario indicare l'assenza di parametri con (). Le parentesi non sono richieste nel caso in cui ci sia solo un parametro (come foo => 1).
statements or expression
Molteplici istruzioni devono essere racchiuse tra parentesi. Una singola espressione non necessita di parantesi. expression è anche l'implicito valore restituito dalla funzione.

Il costruttore Function

Nota: l'utilizzo del costruttore Function per creare funzioni non è raccomandato, poichè richiede che il corpo della funzione sia scritto come stringa, fatto che può comportare una mancata ottimizzazione da parte di alcuni motori javascript e causare altri problemi.

Come tutti gli altri oggetti, un oggetto Function può essere creato utilizzando l'operatore new:

new Function (arg1, arg2, ... argN, functionBody)
arg1, arg2, ... argN
Zero o più nomi da usare come nomi formali di argomenti. Ciascun nome deve essere rappresentato da una stringa testuale che sia conforme alle norme che regolano la definizione di identificatori JavaScript validi, oppure da una lista di stringhe testuali, separate da una virgola; per esempio: "x", "theValue", oppure "a,b".
functionBody
Una stringa testuale che contenga le istruzioni Javascript comprese nella definizione della funzione.

Invocare il costruttore Function come funzione ( senza utilizzare l'operatore new ) ha lo stesso effetto di quando lo si invoca come costruttore.

Il costruttore GeneratorFunction

Nota: le espressioni di funzione a freccia ( arrow function expression ) sono una tecnologia sperimentale, parte della proposta ECMAScript 6, e non sono ancora completamente supportate dai browser.

Nota: il costruttore GeneratorFunction non è un oggetto globale, ma può essere ottenuto dall'istanza della funzione generatrice ( vedi GeneratorFunction per maggiori dettagli ).

Nota: l'utilizzo del costruttore GeneratorFunction per creare funzioni non è raccomandato, poichè richiede che il corpo della funzione sia scritto come stringa, fatto che può comportare una mancata ottimizzazione da parte di alcuni motori javascript e causare altri problemi.

Come tutti gli altri oggetti, un oggetto GeneratorFunction può essere creato utilizzando l'operatore new:

new GeneratorFunction (arg1, arg2, ... argN, functionBody)
arg1, arg2, ... argN
Zero o più nomi da usare come nomi formali di argomenti. Ciascun nome deve essere rappresentato da una stringa testuale che sia conforme alle norme che regolano la definizione di identificatori JavaScript validi, oppure da una lista di stringhe testuali, separate da una virgola; per esempio: "x", "theValue", oppure "a,b".
functionBody
Una stringa testuale che contenga le istruzioni Javascript comprese nella definizione della funzione.

Invocare il costruttore Function come funzione ( senza utilizzare l'operatore new ) ha lo stesso effetto di quando lo si invoca come costruttore.

I parametri di una funzione

Nota: i parametri di default ed i parametri rest sono tecnologie sperimentali, parte della proposta  ECMAScript 6, e non sono ancora completamente supportati dai browser.

Parametri di default

La sintassi per definire i valori di default dei parametri di una funzione permette di inizializzare i parametri formali con valori di default, sempre che non venga passato il valore undefined oppure non venga passato alcun valore. Per maggiori dettagli, vedi default parameters.

I parametri Rest

La sintassi per i parametri rest permette di rappresentare un indefinito numero di argomenti come un array. Per maggiori dettagli, vedi rest parameters.

L'oggetto arguments

È possibile riferirsi agli argomenti di una funzione, all'interno della funzione, utilizzando l'oggetto arguments. Vedi arguments.

  • arguments: un oggetto, strutturato come un array, contenente gli argomenti passati alla funzione in esecuzione.
  • arguments.callee : la funzione in esecuzione.
  • arguments.caller : la funzione che ha invocato la funzione in esecuzione.
  • arguments.length: il numero degli argomenti passati alla funzione.

Definire metodi

Funzioni Getter e setter

È possibile definire metodi getter ( accessor method: metodi per l'accesso al valore di una variabile privata ) e metodi setter ( mutator method: metodi per la modifica del valore di una variabile privata ) per qulasiasi oggetto standard built-in o per qualsiasi oggetto definito dall'utente che supporti l'aggiunta di nuove proprietà. La sintassi da usare per la definizione di metodi getter e setter utilizza la sintassi per la definizione di valori letterali.

get

Lega ( bind ) una proprietà di un oggetto ad una funzione, che verrà invocata ogni volta in cui si cercherà di leggere il valore di quella proprietà.

set
Lega ( bind ) una proprietà di un oggetto alla funzione da invocare ogni volta in cui si cercherà di modificare il valore di quella proprietà.

Sintassi per la definizione dei metodi

Nota: le definizioni dei metodi sono tecnologie sperimentali, parte della proposta  ECMAScript 6, e non sono ancora completamente supportate dai browser.

A partire da ECMAScript 6, è possibile definire propri metodi usando una sintassi più breve, simile alla sintassi usata per i metodi getter e setter. Vedi method definitions per maggiori informazioni.

var obj = {
  foo() {},
  bar() {}
};

Il costruttore Function vs. la dichiarazione di funzione vs. l'espressione di funzione

Compara i seguenti esempi:

Una funzione definita con la dichiarazione di funzione:

function multiply(x, y) {
   return x * y;
}

Una espressione di funzione di una funzione anonima ( senza nome ), assegnata alla variabile multiply:

var multiply = function(x, y) {
   return x * y;
};

Una espressione di funzione di una funzione chiamata func_name , assegnata alla variabile multiply:

var multiply = function func_name(x, y) {
   return x * y;
};

Differenze

Tutti e tre gli esempi fanno più o meno la stessa cosa, con qualche piccola differenza:

C'è una differenza tra il nome di una funzione e la variabile alla quale la funzione viene assegnata. Il nome di una funzione non può essere modificato, mentre la variabile alla quale viene assegnata la funzione può essere riassegnata. Il nome di una funzione può essere utilizzato solo all'interno del corpo della funzione. Tentare di utilizzarlo al di fuori del corpo della funzione genererà un errore ( oppure restituirà undefined se il nome della funzione era stato precedentemente dichiarato con un'istruzione var ). Per esempio:

var y = function x() {};
alert(x); // throws an error

Il nome di una funzione appare anche quando la funzione viene serializzata usando il metodo toString applicato alla funzione.

Dall'altro lato, la variabile alla quale viene assegnata la funzione è limitata solo dal suo scope, la cui inclusione è garantita al momento della dichiarazione di funzione.

Come si può vedere dal quarto esempio, il nome della funzione può essere diverso dal nome della variabile alla quale la funzione viene assegnata. I due nomi non hanno alcuna relazione tra loro. Una dichiarazione di funzione crea anche una variabile con lo stesso nome della funzione. Quindi, diversamente dalle funzioni definite attraverso un'espressione di funzione, le funzioni definite attraverso una dichiarazione di funzione offrono la possibilità di accedere ad esse attraverso il loro nome, almeno all'interno dello scope in cui erano state definite.

Una funzione definita con il costruttore 'new Function' non possiede un nome. Tuttavia, nel motore JavaScript SpiderMonkey, la forma serializzata della funzione mostra il nome "anonymous". Per esempio, il codice alert(new Function()) restituisce:

function anonymous() {
}

Poichè la funzione, in realtà, non ha un nome, anonymous non è una variabile alla quale si potrà accedere, all'interno della funzione. Per esempio, il seguente codice restituirebbe un errore:

var foo = new Function("alert(anonymous);");
foo();

Diversamente da quanto accade con le funzioni definite con espressioni di funzione o con il costruttore Function, una funzione definita con una dichiarazione di funzione può essere usata prima della dichiarazione di funzione stessa. Per esempio:

foo(); // alerts FOO!
function foo() {
   alert('FOO!');
}

Una funzione definita da un'espressione di funzione eredita lo scope corrente. Vale a dire, la funzione forma una chiusura. Dall'altro lato, una funzione definita dal costruttore Function non eredita alcuno scope, se non quello globale ( che eredita qualsiasi funzione ).

Le funzioni definite con espressioni di funzione e dichiarazioni di funzione vengono analizzate ( parsed ) solo una volta, mentre quelle definite con il costruttore Function no. Vale a dire, la stringa testuale del corpo della funzione passata al costruttore Function deve essere analizzata ( parsed ) ogni volta in cui viene invocato il costruttore. Sebbene un'espressione di funzione crei ogni volta una chiusura, il corpo della funzione non viene rianalizzato ( reparsed ), così le espressioni di funzione sono ancora più veloci del "new Function(...)". Quindi, il costruttore Function dovrebbe, generalmente, essere evitato dove possibile.

Occorre tenere presente, tuttavia, che le espressioni di funzione e le dichiarazioni di funzione annidate in una funzione generata dall'analisi ( parsing ) di una stringa del costruttore Function non vengono analizzate ( parsed ) continuamente. Per esempio:

var foo = (new Function("var bar = \'FOO!\';\nreturn(function() {\n\talert(bar);\n});"))();
foo(); // The segment "function() {\n\talert(bar);\n}" of the function body string is not re-parsed.

Una dichiarazione di funzione è molto facilmente ( e spesso, anche non intenzionalmente ) convertita in un'espressione di funzione. Una dichiarazione di funzione cessa di essere tale quando:

  • diventa parte di un'espressione
  • non è più un "elemento sorgente" di una funzione o dello stesso script. Un "elemento sorgente" ( source element ) è un'istruzione non annidata, presente nello script o nel corpo della funzione:
var x = 0;               // source element
if (x == 0) {            // source element
   x = 10;               // not a source element
   function boo() {}     // not a source element
}
function foo() {         // source element
   var y = 20;           // source element
   function bar() {}     // source element
   while (y == 10) {     // source element
      function blah() {} // not a source element
      y++;               // not a source element
   }
}

Examples

// function declaration
function foo() {}

// function expression
(function bar() {})

// function expression
x = function hello() {}


if (x) {
   // function expression
   function world() {}
}


// function declaration
function a() {
   // function declaration
   function b() {}
   if (0) {
      // function expression
      function c() {}
   }
}

Definire una funzione in modo condizionato

Le funzioni possono essere definite in modo condizionato, utilizzando sia le istruzioni di funzione ( un'estensione prevista nello standard ECMA-262 Edition 3 ), sia il costruttore Function. Da notare, però, che le  istruzioni di funzione non sono più accettate in ES5 strict mode. Inoltre, questa funzionalità non funziona bene attraverso più browser, quindi sarebbe meglio non farci affidamento.

Nello script seguente, la funzione zero non verrà mai definita e non potrà mai essere invocata, visto che 'if (0)' restituisce sempre false:

if (0) {
   function zero() {
      document.writeln("This is zero.");
   }
}

Se la condizione diventasse 'if (1)', la funzione zero verrebbe definita.

Nota: sebbene questo tipo di funzione sembri una dichiarazione di funzione, in realtà siamo di fronte ad una espressione ( o statement, o istruzione ), poichè la dichiarazione è annidata all'interno di un'altra istruzione. Vedi le differenze tra dichiarazioni di funzione ed espressioni di funzione.

Nota: alcuni motori JavaScript, eslcuso SpiderMonkey, trattano, non correttamente, qualsiasi espressione di funzione in modo da assegnare loro un nome, al momento della definizione. Questo comporterebbe che la funzione zero sarebbe comunque definita, anche nell'eventualità che la condizione if restituisse sempre false. Un modo più sicuro per definire le funzioni in modo condizionato è di definirle come funzioni anonime ed assegnarle, poi, ad una variabile:

if (0) {
   var zero = function() {
      document.writeln("This is zero.");
   }
}

Esempi

Restituire un numero formattato

La seguente funzione restituisce ( return ) una stringa contenente la rappresentazione formattata di un numero, completato ( padded ) con degli zero iniziali.

// This function returns a string padded with leading zeros
function padZeros(num, totalLen) {
   var numStr = num.toString();             // Initialize return value as string
   var numZeros = totalLen - numStr.length; // Calculate no. of zeros
   for (var i = 1; i <= numZeros; i++) {
      numStr = "0" + numStr;
   }
   return numStr;
}

Queste istruzioni invocano la funzione padZeros.

var result;
result = padZeros(42,4); // returns "0042"
result = padZeros(42,2); // returns "42"
result = padZeros(5,4);  // returns "0005" 

Determinare l'esistenza di una funzione

È possibile determinare se una funzione esiste, utilizzando l'operatore typeof. Nell'esempio seguente, viene eseguito un test per determinare se l'oggetto window ha una proprietà, che sia una funzione, chiamata noFunc. Se così, la funzione verrà utilizzata; in caso contrario, verrà eseguita una qualsiasi altra azione.

 if ('function' == typeof window.noFunc) {
   // use noFunc()
 } else {
   // do something else
 }

Da notare che nel test if  viene usato un riferimento a noFunc  — senza usare le parentesi "()" dopo il nome della funzione: in questo modo, la funzione non viene invocata.

Specifications

Specification Status Comment
ECMAScript 1st Edition. Standard Initial definition. Implemented in JavaScript 1.0
ECMAScript 5.1 (ECMA-262)
The definition of 'Function Definition' in that specification.
Standard  
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Function definitions' in that specification.
Standard New: Arrow functions, Generator functions, default parameters, rest parameters
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'function*' in that specification.
Standard Initial definition.
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Arrow Function Definitions' in that specification.
Standard Initial definition.

Browser compatibility

Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari
Basic support (Yes) (Yes) (Yes) (Yes) (Yes)
Generator function 39 26.0 (26.0) ? 26 ?
Arrow function Not supported 22.0 (22.0) Not supported Not supported Not supported
Feature Android Chrome for Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
Basic support (Yes) (Yes) (Yes) (Yes) (Yes) (Yes)
Generator function ? 39 26.0 (26.0) ? 26 ?
Arrow function Not supported Not supported 22.0 (22.0) Not supported Not supported Not supported

See also

Tag del documento e collaboratori

 Hanno collaborato alla realizzazione di questa pagina: lvzndr, ungarida, teoli, Salvo1402
 Ultima modifica di: lvzndr,