From 30feb96f6084a2fb976a24ac01c1f4a054611b62 Mon Sep 17 00:00:00 2001 From: Florian Merz Date: Thu, 11 Feb 2021 14:47:54 +0100 Subject: unslug it: move --- .../control_flow_and_error_handling/index.html | 461 +++++++++++++ .../guide/details_of_the_object_model/index.html | 727 +++++++++++++++++++++ files/it/web/javascript/guide/functions/index.html | 646 ++++++++++++++++++ .../javascript/guide/grammar_and_types/index.html | 659 +++++++++++++++++++ files/it/web/javascript/guide/index.html | 124 ++++ .../web/javascript/guide/introduction/index.html | 140 ++++ .../guide/iterators_and_generators/index.html | 162 +++++ .../guide/loops_and_iteration/index.html | 340 ++++++++++ .../guide/regular_expressions/index.html | 647 ++++++++++++++++++ 9 files changed, 3906 insertions(+) create mode 100644 files/it/web/javascript/guide/control_flow_and_error_handling/index.html create mode 100644 files/it/web/javascript/guide/details_of_the_object_model/index.html create mode 100644 files/it/web/javascript/guide/functions/index.html create mode 100644 files/it/web/javascript/guide/grammar_and_types/index.html create mode 100644 files/it/web/javascript/guide/index.html create mode 100644 files/it/web/javascript/guide/introduction/index.html create mode 100644 files/it/web/javascript/guide/iterators_and_generators/index.html create mode 100644 files/it/web/javascript/guide/loops_and_iteration/index.html create mode 100644 files/it/web/javascript/guide/regular_expressions/index.html (limited to 'files/it/web/javascript/guide') diff --git a/files/it/web/javascript/guide/control_flow_and_error_handling/index.html b/files/it/web/javascript/guide/control_flow_and_error_handling/index.html new file mode 100644 index 0000000000..76e72f5cba --- /dev/null +++ b/files/it/web/javascript/guide/control_flow_and_error_handling/index.html @@ -0,0 +1,461 @@ +--- +title: Controllo del flusso di esecuzione e gestione degli errori +slug: Web/JavaScript/Guida/Controllo_del_flusso_e_gestione_degli_errori +tags: + - Controllo di flusso + - Guide + - JavaScript + - Principianti + - 'l10n:priority' +translation_of: Web/JavaScript/Guide/Control_flow_and_error_handling +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Grammar_and_types", "Web/JavaScript/Guide/Loops_and_iteration")}}
+ +

JavaScript prevede un insieme di istruzioni compatto, specifico per il controllo del flusso di esecuzione, che si può utilizzare per aggiungere un'elevata interattività alle proprie applicazioni. Questo capitolo fornisce una panoramica su queste istruzioni.

+ +

Il JavaScript reference contiene dettagli esaustivi sulle istruzioni di questo capitolo. Il carattere punto e virgola (;) è usato per separare le varie istruzioni del codice JavaScript.

+ +

Ogni espressione JavaScript è a sua volta un'istruzione. Si veda a riguardo Espressioni ed operatori per una completa descrizione delle espressioni.

+ +

Costrutto di blocco

+ +

Un costrutto fondamentale è il blocco, usato per raggruppare insieme più istruzioni, delimitato da un paio di parentesi graffe ({}):

+ +
{
+  istruzione_1;
+  istruzione_2;
+  .
+  .
+  .
+  istruzione_n;
+}
+
+ +

Esempi

+ +

Il blocco è comunemente usato assieme alle istruzioni per il controllo del flusso (e.g. if, for, while).

+ +
while (x < 10) {
+  x++;
+}
+
+ +

Qui, { x++; } rappresenta un blocco.

+ +

Importante: JavaScript prima di ECMAScript2015 non aveva la visibilità di blocco. Le variabili definite nel blocco hanno una visibilità a livello di funzione o di script in cui sono contenute e l'effetto di assegnare loro un valore persiste oltre il blocco stesso. Cioè il blocco non definisce un campo di visibilità. I blocchi "Indipendenti" ("Standalone" blocks) in JavaScript possono dare un risultato differente da quello che avrebbero prodotto in C o in Java. Per esempio:

+ +
var x = 1;
+{
+  var x = 2;
+}
+console.log(x); // produce 2
+
+ +

Risulta 2 perché l'istruzione di definizione var x dentro il blocco ha lo stesso campo di visibilità dell'istruzione var x al di fuori del blocco. Mentre in C o Java, il codice equivalente avrebbe prodotto 1.

+ +

A partire da ECMAScript2015, la dichiarazione di variabile con l'istruzione let ha visibilità di blocco. Si veda il riferimento a {{jsxref("Statements/let", "let")}} per ulteriori informazioni.

+ +

Costrutti Condizionali

+ +

Un costrutto condizionale è un insieme di istruzioni che vengono eseguite se una specifica condizione risulta vera. JavaScript prevede due costrutti condizionali: if...else e switch.

+ +

Costrutto if...else

+ +

Si usa il costrutto if per eseguire un blocco di istruzioni se una condizione logica è vera. Si usa la clausola opzionale else per eseguire istruzioni nel caso in cui la stessa condizione sia falsa. Un costrutto if...else si presenta come qui sotto:

+ +
if (condizione) {
+  istruzioni_se_vera_la_condizione;
+} else {// opzionale
+  istruzioni_se_falsa_la_condizione;
+}
+ +

Qui la condizione è qualsiasi espressione che sia valutabile come vera oppure falsa (true o false). Si veda il riferimento a Boolean per una spiegazione su cosa possa essere valutabile come true o false. Se la condizione viene valutata true, istruzioni_se_vera_la_condzione verrà eseguito, altrimenti verrà eseguito istruzioni_se_falsa_la_condzione. istruzioni_se_vera_la_condzione e istruzioni_se_falsa_la_condzione possono essere qualsiasi istruzione, incluso un altro if.

+ +

Si possono pure combinare le istruizioni else if per testare molteplici condizioni in sequenza, come il seguente codice dimostra:

+ +
if (condizione_1) {
+  istruzione_1;
+} else if (condizione_2) {
+  istruzione_2;
+} else if (condizione_n) {
+  istruzione_n;
+} else {
+  ultima_istruzione;
+}
+
+ +

Nel caso di condizioni plurime solo la prima che sia valutata come vera sarà eseguita. Per eseguire più istruzioni si devono raggruppare in un blocco ({ ... }) . In generale è buona pratica usare un blocco specialmente se si usano if annidati:

+ +
if (condizione) {
+  istruzione_1_eseguita_se_vera_la_condizione;
+  istruzione_2_eseguita_se_vera_la_condizione;
+  ...
+} else {
+  istruzione_3_eseguita_se_falsa_la_condizione;
+  istruzione_4_eseguita_se_falsa_la_condizione;
+  ...
+}
+
+ +
Non è consigliabile usare la semplice assegnazione in una espressione condizionale, perché l'assegnamento potrebbe essere confuso con il segno di uguaglianza quando si dia un'occhiata rapida al codice. Ad esempio, non si usi il seguente codice:
+ +
+ +
if (x = y) {// questa è una assegnazione
+  /* istruzioni qui */
+}
+ +

Se si deve proprio usare un assegnamento in una espressione condizionale è pratica comune aggiungere un paio di parentesi tonde attorno all'assegnamento. Per esempio:

+ +
if ((x = y)) {
+  /* istruzioni qui */
+}
+
+ +

Valori valutabili a false

+ +

I seguenti valori si valutano a false (sono anche detti {{Glossary("Falsy")}} value):

+ + + +

Tutti gli altri valori, inclusi gli oggetti, saranno valutati a true in una istruzione condizionale.

+ +

Non si confonda il valori primitivi booleani true e false con i valori true e false dell'oggetto {{jsxref("Boolean")}}. Ad esempio:

+ +
var b = new Boolean(false);
+
+if (b) // questa condizione è valutata a true
+       // perché 'b' in questo caso è un oggetto
+       // e si sa che tutti gli oggetti sono valutati a true
+
+if (b == true) // mentre questa a false,
+               // perché si va a prelevare il contenuto dell'oggetto 'b' che è false
+
+ +

Esempi

+ +

Nell'esempio a seguire la funzione controllaDati ritorna true se il numero di caratteri contenuti nella proprietà value dell'oggetto Text (treCaratteri) è tre, altrimenti mostra un popup di alert e, infine, ritorna il valore false.

+ +
function controllaDati() {
+  if (document.form1.treCaratteri.value.length == 3) {
+    return true;
+  } else {
+    alert("Immetti esattemente tre caratteri. " +
+    document.form1.treCaratteri.value + " non è valido.");
+    return false;
+  }
+}
+
+ +

Costrutto switch

+ +

Un costrutto switch permette ad un programma di valutare un'espressione e tentare di trovare la corrispondenza esatta tra il valore risultante dalla valutazione dell'espressione e l'etichetta specificata nella clausola case. Se si incontra una corrisopondenza il programma eseguirà le istruzioni associate. Un costrutto switch si presenta  come nell'esempio qui sotto riportato:

+ +
switch (espressione) {
+  case etichetta_1:
+    istruzione_1
+    [break;]// opzionale
+  case etichetta_2:
+    istruzione_2
+    [break;]
+    ...
+  default:
+    istruzioni_di_default
+    [break;]
+}
+
+ +

Il programma cerca la prima corrispondenza tra il valore ottentuto della valutazione dell'espressione e l'etichetta nella clausola case, poi trasferisce il controllo al corpo della medesima clausola eseguendo le istruzioni relative. Se non è stata trovata alcuna corrispondeza il programma va alla clausola opzionale default e, se la trova, esegue le istruizioni ad essa relative. Se non è stata data alcuna clausola default il programma continuerà con l'istruzione successiva al blocco switch. La clausola default è l'ultima che appare nel blocco switch, ma questa è una convenzione non la regola.

+ +

Il break opzionale, associato con ogni clausola case, assicura che il programma esca dal blocco switch una volta eseguite le istruzioni associate alla clausola e continui la sua esecuzione all'istruzione che segue il costrutto switch. Se il break è omesso il programma continua la sua esecuzione all'istruzione successiva nello stesso costrutto switch, ciò significa che eseguirà le istruzioni associate alla clausola case/default (se ci sono) successiva a quella appena terminata.

+ +

Esempi

+ +

Nel seguente esempio, se la variabile tipidifrutto contiene "Banane", il programma cercherà la corrispondente clausola case "Banane" ed eseguirà le istruzioni associate. Quando incontra il break, il porgramma esce dallo switch ed esegue l'istruzione successiva al blocco di switch. Se, invece, il break fosse stato omesso le istuzioni collegate con la clausola case "Ciliege" sarebbero state eseguite.

+ +
switch (tipidifrutta) {
+  case "Arance":
+    console.log("Le Arance sono a €0.59 il chilo.");
+    break;
+  case "Mele":
+    console.log("Le mele sono a €0.32 il chilo.");
+    break;
+  case "Banane":
+    console.log("Le Banane sono €0.48 il chilo.");
+    break;
+  case "Ciliege":
+    console.log("Le ciliege sono s €3.00 il chilo.");
+    break;
+  case "Mango":
+    console.log("Il Mango è è €0.56 il chilo.");
+    break;
+  case "Papaia":
+    console.log("Il Mango e la Papaia sono a €2.79 il chilo.");
+    break;
+  default:
+    console.log("Spiacenti, abbiano terminato " + tipidifrutta + ".");
+}
+console.log("C'è qualcos'altro che ti piace?");
+ +

Costrutti di gestione delle Eccezioni

+ +

Si può sollevare/generare un'eccezione attraverso l'istruzione throw e si possono gestire usando il costrutto try...catch.

+ + + +

Tipi di eccezione

+ +

Quasi ogni tipo di oggetto può essere usato per sollevare/generare un'eccezione JavaScript. Tuttavia non tutti gli oggetti utili a questo scopo sono creati in modo eguale. Mentre è abbastanza comune usare numeri o stringhe per indicare un errore, è più efficace usare uno dei tipi di eccezione specificatamente creati a questo scopo:

+ + + +

Istruzione throw

+ +

Si usa l'istruzione throw per sollevare/generare un'eccezione. Quando si genera un'eccezione va specificata un'espressione che produca un valore da usarsi come eccezione:

+ +
throw espressione;
+
+ +

Si può usare una qualsiasi espressione con l'istruzione throw e non solamente espressioni di un certo tipo. Il seguente pezzo di codice lo dimostra:

+ +
throw "Errore2";  // tipo String
+throw 42;         // tipo Number
+throw true;       // tipo Boolean
+throw {toString: function() { return "Sono un oggetto!"; } };
+
+ +
Note: Si può specificare un oggetto quando si genera un'eccezione. Si può poi far riferimento alle proprietà dell'oggetto nel blocco catch. Il seguente esempio crea un oggetto myUserException del tipo UserException e lo usa nell'istruzione throw.
+ +
// Crea un oggetto di tipo UserException
+function UserException(messaggio) {
+  this.message = messaggio;
+  this.name    = "UserException";
+}
+
+// Sovrascrive il metodo toString() affinché l'oggetto
+// dia una descrizione di se stesso al momento di usarlo come stringa.
+// (e.g. come messaggio nella console degli errori)
+UserException.prototype.toString = function() {
+  return this.name + ': "' + this.message + '"';
+}
+
+// Crea un'istanza dell'oggetto e lo usa nell'istruzione throw
+throw new UserException("Valore troppo alto!);
+ +

Costrutto try...catch (... finally)

+ +

Il costrutto try...catch racchiude un blocco di istruzioni, che potrebbero generare un'eccezione, e specifica uno o più azioni per gestire l'eccezione che potrebbe essere sollevata. Se viene sollevata un'eccezione il costrutto try...catch la cattura.

+ +

Il costrutto try...catch è costituito da un blocco try, che contiene a sua volta uno o più istruzioni, e da al più (vedi nota più sotto) un blocco catch, contenenti istruzioni per gestire l'eccezione che eventulmente sarà sollevata all'interno del blocco try.  Cioè si vorrebbe che il blocco try fosse eseguito senza errori, ma se non fosse possibile si vuole che l'esecuzione passi al blocco catch. Se un'istruzione contenuta nel blocco (o in una funzione chiamata all'interno del blocco) try genera un'eccezione, il controllo passa immediatamente al blocco catch. Se nessuna eccezione è sollevata all'interno del blocco try, il blocco catch è semplicemente ignorato. Il blocco finally (opzionale se c'è il blocco catch, ma necessario se manca quest'utimo) è eseguito subito dopo l'esecuzione dei blocchi try/catch, ma prima di una qualsiasi istruzione che segua gli stessi try...catch...finally.

+ +
+

In realtà il browser Firefox è in grado di suppostare i blocchi catch condizionati, oltre quello incondizionato, rendendo virtualmeente illimitata la definizione di più di un blocco catch per uno stesso blocco try. Tuttavia questa caratteristica non è standard e se ne scoraggia l'uso, si veda a proposito la referenza {{jsxref("Statements/try...catch", "try...catch")}}.

+
+ +

L'esempio che segue usa il costrutto di try...catch. L'esempio chiama una funzione che ritorna il nome del mese estratto da un array grazie al parametro mo passato alla funzione. Se il valore passato non corrispondesse al numero di mese consentito (tra 1 e 12), un'eccezione verrebbe sollevata col valore "numeroMeseNonValido" e il blocco catch assegnerebbe alla variabile nomeDelMese il vaore di "sconoscuto".

+ +
function getNomeDelMese(mo) {
+  mo = mo - 1; // Sistema il numero del mese (1 = Gen, 12 = Dic)
+  var mesi = ["Gen","Feb","Mar","Apr","Mag","Giu","Lug",
+                "Ago","Set","Ott","Nov","Dic"];
+  if (mesi[mo]) {
+    return mesi[mo];
+  } else {
+    throw "numeroMeseNonValido"; //l'istruzione throw è usata qui
+  }
+}
+
+try { // blocco try
+  nomeDelMese = getNomeDelMese(mese); // la funzione potrebbe sollevare un'eccezione
+}
+catch (eccezione) {
+  nomeDelMese = "sconosciuto";
+  logDegliErrori(eccezione); // Passa l'eccezione a un gestore -> una propria funzione
+
+ +

Il blocco catch

+ +

Si può usare il blocco catch per gestire le eccezioni che possono essere generate nel blocco try.

+ +
catch (catchID) {
+  // istruzioni
+}
+
+ +

Il blocco catch viene specificato un identificatore (catchID nel precedente esempio) che conterrà il valore specificato nell'istruzione throw. Si può usare questo identificatore per ottenere informazione ulteriori circa l'eccezione che è stata generata. JavaScript crea questo identificatore quando si entra nel blocco catch. L'identificatore è valido solo per la durata in esecuzione del blocco catch stesso, infatti usciti dal blocco catch termina la sua esistenza e non è più disponibile.

+ +

Per esempio, il seguente codice solleva un'eccezione. Quando l'eccezione si realizza il controllo passa al blocco catch.

+ +
try {
+  throw "miaEccezione"; // genera una eccezione
+}
+catch (eccezione) { // "eccezione" è l'identificatore con conterrà
+  // l'oggetto usato nell'istruzione thrown, in questo caso la stringa "miaEccezione"
+
+  // istruzioni che gestiscono l'eccezione
+  gestisciErrori(eccezione); // passa l'oggetto eccezione al gestore
+}
+
+ +

Il blocco finally

+ +

Il blocco finally contiene istruzioni che vengono eseguite subito dopo i blocchi try ed eventualmente catch, ma prima di ogni altra istruzione che segua il costrutto try...catch...finally. Il blocco finally è eseguito indipendentemente dal fatto che un'eccezione sia o meno generata. Se un'eccezione viene sollevata le istruzioni nel blocco finally saranno eseguite anche se il blocco catch corrispondente la gestisce.

+ +

Si può usare il blocco finally per permettere agli script di terminare elegantemente in presenza di un'eccezione, ad esempio, se si deve liberare una risorsa che lo script trattiene. Il seguente esempio apre un file e lo usa (JavaScript lato server permette di accedere al file system). Se si solleva un'eccezione mentre il file è aperto il blocco finally chiude il file prima che lo script termini/fallisca.

+ +
apriMioFile();
+try {
+  ScriviMioFile(dati); //Qui si può verificare un'eccezione/errore
+} catch(e) {
+  gestisciErrore(e); // Se avviene un errore lo si gestisce
+} finally {
+  chiudiMioFile(); // chiude comunque la risorsa
+}
+
+ +

Se il blocco finally ritorna un valore questo diviene il valore ritornato dall'intero costrutto try-catch-finally a dispetto di qualsiasi valore eventualmente ritornato dai blocchi try/catch:

+ +
function f() {
+  try {
+    console.log(0);
+    throw "fasulla";
+  } catch(e) {
+    console.log(1);
+    return true; // quasta istruzione di ritorno è sospesa
+                 // finché il blocco finally non termina
+    console.log(2); // istruzione non raggiungibile
+  } finally {
+    console.log(3);
+    return false; // sovrascrive il precedente "return"
+    console.log(4); // istruzione non raggiungibile
+  }
+  // "return false" è eseguito ora
+  console.log(5); // istruzione non raggiungibile
+}
+f(); // nel log a console troviamo stampato: 0, 1, 3 e false
+
+ +

La sovrascrittura dei valori di ritorno, da parte del blocco finally, colpisce anche le eccezioni generate e/o ri-generate dentro il blocco catch:

+ +
function f() {
+  try {
+    throw "fasulla";
+  } catch(e) {
+    console.log('catturata l\'eccezione interna "fasulla"');
+    throw e; // Quasta istruzione throw è sospesa
+             // finché il blocco finally non termina
+  } finally {
+    return false; // sovrascrive il precedente "throw"
+  }
+  // "return false" è eseguita ora
+}
+
+try {
+  f();
+} catch(e) {
+  // Questo blocco non sarà mai raggiunto in quanto l'istruzione
+  // throw dentro il blocco catch (vedi più sopra) è sovrascritta
+  // dal return della clausola finally
+  console.log('catturata l\'eccezione esterna "fasulla"');
+}
+
+// OUTPUT
+// catturata l'eccezione interna "fasulla"
+ +

try...catch innestati

+ +

Si possono annidare try...catch. Se un blocco try...catch interno non ha il blocco catch (in questo caso è d'obbligo che ci sia il blocco finally, anche vuoto, altrimenti si ha un errore sintattico), il blocco catch, del costrutto try...catch che lo racchiude, catturerà l'eventuale eccezione.

+ +
try{// try-catch esterno
+  try{
+   // try-finally interno
+    throw "eccezione fasulla";
+  }
+  // Manca il blocco catch, ma deve esserci il blocco finally
+  finally{
+    // vuoto
+  }
+}
+catch(e){
+  // Viene catturata l'eccezione sollevata dal blocco più interno
+  console.log("cattura esterna: " + e);
+}
+
+//nella console sarà stampato: "cattura esterna: eccezione fasulla"
+ +

Utilizzo degli oggetti Error

+ +

A seconda del tipo di errore se si è in grado di usare le proprietà 'name' e 'message' si può avere un messaggio più ricco. 'name' fornisce la classe generale dell'Error (e.g., 'DOMException' o 'Error'), mentre 'message' generalmente fornisce un messaggio più conciso rispetto al convertire l'oggetto corrispondente all'errore in una stringa.

+ +

Se si crea una propria eccezione affiché ci si avvantaggi di queste proprietà (come nel caso, ad esempio, del blocco catch che non discrimini tra l'oggetto rappresentante la propria eccezione e quello di sistema) si può usare il costruttore dell'oggetto Error:

+ +
function faiQualcosaSoggettaAdErrore () {
+  if (codiceCheProduceUnErrore()) {
+    throw (new Error('Il Messaggio'));
+  } else {
+    faiQualcosaPerOttenereUnEorreDiJavascript();
+  }
+}
+....
+try {
+  faiQualcosaSoggettaAdErrore();
+} catch (e) {
+  console.log(e.name);    // Scrive a console: 'Error'
+  console.log(e.message); // Scrive a console: 'Il Messaggio' o un messaggio di errore di JavaScript)
+}
+ +

I Promise

+ +

A partire da ECMAScript2015, JavaScript acquisisce il supporto agli oggetti {{jsxref("Promise")}} permettendo di controllare l'esecuzione di operazioni in modo differito e asincrono.

+ +

Un Promise può essere in uno di questi stati:

+ + + +

+ +

Caricare un'immagine con XHR

+ +

Un esempio di semplice utilizzo di un Promise e XMLHttpRequest per caricare un'immagine è disponibile nel repository promise-test di MDN GitHub. Si può anche vedere in azione. Ogni passo  è commentato e ti permette di seguire il Promise e l'architettura XHR da vicino. Qui, invece, la versione non commentata che mostra l'utilizzo del Promise per darti un'idea del suo funzionamento:

+ +
function caricaImmagine(url) {
+  return new Promise(function(resolve, reject) {
+    var request = new XMLHttpRequest();
+    request.open('GET', url);
+    request.responseType = 'blob';
+    request.onload = function() {
+      if (request.status === 200) {
+        resolve(request.response);
+      } else {
+        reject(Error('L\'immagine non è stata caricata con successo; codice di errore:'
+                     + request.statusText));
+      }
+    };
+    request.onerror = function() {
+      reject(Error('C\'è stato un errore di connessione'));
+    };
+    request.send();
+  });
+}
+ +

Per informazioni più dettagliate si veda la pagina di riferimento relativa al {{jsxref("Promise")}}.

+ +
{{PreviousNext("Web/JavaScript/Guide/Grammar_and_types", "Web/JavaScript/Guide/Loops_and_iteration")}}
diff --git a/files/it/web/javascript/guide/details_of_the_object_model/index.html b/files/it/web/javascript/guide/details_of_the_object_model/index.html new file mode 100644 index 0000000000..1e2d4dc74f --- /dev/null +++ b/files/it/web/javascript/guide/details_of_the_object_model/index.html @@ -0,0 +1,727 @@ +--- +title: Dettagli del modello a oggetti +slug: Web/JavaScript/Guida/Dettagli_Object_Model +tags: + - Guide + - Intermediate + - JavaScript +translation_of: Web/JavaScript/Guide/Details_of_the_Object_Model +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Working_with_Objects", "Web/JavaScript/Guide/Iterators_and_Generators")}}
+ +
+

Il contenuto di questo articolo è in discussione. Lascia un feedback e aiutaci a rendere migliore questa pagina: {{bug(1201380)}}.

+
+ +

JavaScript è un linguaggio ad oggetti basato su prototipi, piuttosto che sulle classi. A causa di questa diversa base, può essere meno evidente come JavaScript permette di creare gerarchie di oggetti e di avere l'ereditarietà delle proprietà e dei loro valori. Questo articolo cerca di chiarire questo aspetto.

+ +

Questo capitolo presuppone una certa familiarità con JavaScript e con l'uso delle funzioni per la creazione di semplici oggetti.

+ +

Linguaggi class-based vs. linguaggi prototype-based

+ +

I linguaggi ad oggetti basati su classi, come Java e C++, si basano su due entità distinte: le classi (classes) e le istanze (instances).

+ + + +

Un linguaggio basato su prototipi, come JavaScript, non fa questa distinzione: ha solo oggetti. Introduce la nozione di oggetto prototipo (prototypical object), un oggetto usato come modello da cui prendere le proprietà iniziali per un nuovo oggetto. Ogni oggetto può specificare le sue proprietà, anche quando viene creato o in fase di esecuzione.Inoltre, ogni oggetto può essere associato ad un altro oggetto come prototipo, consentendo al secondo oggetto di condividere le proprietà del primo.

+ +

Definizione di una classe

+ +

Nei linguaggi basati su classi, le classi vengono definite in class definition separate. In queste definizioni è possibile specificare metodi speciali, chiamari costruttori (constructors), per creare istanze della classe. Un costruttore può specificare i valori iniziali per le proprietà dell'istanza ed eseguire altre elaborazioni adatte al momento della creazione. Per creare le istanze di una classe si utilizza l'operatore new associato al metodo costruttore.

+ +

JavaScript segue un modello simile, ma non prevede la definizione della classe separata dal costruttore. Invece, per creare oggetti con un particolare set di proprietà e valori si definisce una funzione costruttore. Ogni funzione JavaScript può essere usata come costruttore. Per creare un nuovo oggetto si utilizza l'operatore new associato a una funzione costruttore.

+ +

Sottoclassi e ereditarietà

+ +

In un linguaggio basato su classi, si crea una gerarchia tra le classi attraverso le definizioni delle classi stesse. All'interno della definizione di una classe è possibile specificare che la nuova classe è una sottoclasse (subclass) di una classe esistente. La sottoclasse eredita tutte le proprietà della superclasse e può inoltre aggiungere nuove proprietà o modificare quelle ereditate. Per esempio, assumiamo che la classe Employee include solo le proprietà name e dept, e Manager è una sottoclasse di Employee che aggiunge la proprietà reports. In questo caso, un'istanza della classe Manager avrà tutte e tre le proprietà: name, dept, e reports.

+ +

JavaScript implementa l'ereditarietà permettendo di associare un oggetto prototipo ad ogni funzione costruttore. Quindi, è possibile ricreare esattamente l'esempio visto in precedenza, ma usando una terminologia leggermente diversa. Innanzitutto  si definisce la funzione costruttore Employee, specificando le proprietà name e dept. In seguito, si definisce la funzione costruttore Manager, chiamando il costruttore Employee e specificando la proprietà reports. Infine, si assegna a un nuovo oggetto derivato da Employee.prototype come il prototipo per la funzione costruttore Manager. Quando si crea un nuovo Manager, questo eredita le proprietà name e dept dall'oggetto Employee.

+ +

Aggiungere e rimuovere proprietà

+ +

Nei linguaggi basati su classi, una classe viene solitamente creata in fase di compilazione mentre le istanze possono essere create in fase di compilazione o in fase di esecuzione. Non è possibile cambiare il numero o il tipo di proprietà di una classe dopo che questa è stata definita. In JavaScript in fase di esecuzione si possono aggiungere o rimuovere proprietà a qualunque oggetto. Se si aggiunge una proprietà a un oggetto che è usato come prototipo per un gruppo di oggetti, anche gli oggetti del gruppo ereditano la nuova proprietà.

+ +

Riepilogo delle differenze

+ +

La tabella seguente fornisce un breve riepilogo di alcune di queste differenze. Il resto di questo capitolo descrive nel detteglio l'uso in JavaScript di costruttori e prototipi per creare una gerarchia di oggetti e lo confronta con la procedura che si userebbe in Java.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Confronto tra il sistema di oggetti basato su classi (Java) e il sistema di oggetti basato su prototipi (JavaScript)
Class-based (Java)Prototype-based (JavaScript)
Classi e istanze sono entità separate.Tutti gli oggetti possono ereditare da un altro oggetto.
Definire una classe con una definizione; istanziare una classe con un metodo costruttoreDefinire e creare una collezione di oggetti con una funzione costruttore.
Creare un singolo oggetto con l'operatore new.Uguale.
Costruire una gerarchia di oggetti usando la definizione di classe per definire le sottoclassi di classi esistenti.Costruire una gerarchia di oggetti assegnando un oggetto come prototipo associato a una funzione costruttore.
Ereditare le proprietà seguendo la catena delle classi.Ereditare le proprietà seguendo la catena dei prototipi.
La definizione di classe specifica tutte le proprietà di tutte le istanze della classe. Non è possibile aggiungere proprietà dinamicamente durante l'esecuzione.La funzione costruttore o il prototipo specificano un set iniziale di proprietà. È possibile aggiungere o rimuovere dinamicamente proprietà ai singoli oggetti o all'intero gruppo di oggetti.
+ +

L'esempio 'dipendente'

+ +

Il resto di questo capitolo usa la gerarchia dei dipendenti mostrata nella figura seguente.

+ +
+
+

Una semplice gerarchia con gli oggetti seguenti:

+ +

+
+ +
+
    +
  • Employee ha le proprietà name (il cui valore di default è una stringa vuota) e dept (il cui valore di default è "general").
  • +
  • Manager è basato su Employee. Aggiunge la proprietà reports  (il cui valore di default è un array vuoto, destinato a contenere una serie di oggetti Employee).
  • +
  • WorkerBee è anch'esso basato su Employee. Aggiunge la proprietà projects (il cui valore di default è un array vuoto, destinato a contenere una serie di stringhe).
  • +
  • SalesPerson è basato su WorkerBee. Aggiunge la proprietà quota (il cui valore di default è 100). Sovrascrive inoltre la proprietà dept con il valore "sales", che indica che tutti i venditori si trovano nello stesso dipartimento.
  • +
  • Engineer è basato su WorkerBee. Aggiunge la proprietà machine (il cui valore di default è una stringa vuota) e sovrascrive la proprietà dept con il valore "engineering".
  • +
+
+
+ +

Creazione della gerarchia

+ +

Ci sono diversi modi per definire una funzione costruttore appropriata per implementare la gerarchia dei dipendenti. Il modo scelto per definirli dipende molto da cosa si vuole riuscire a fare nella propria applicazione.

+ +

Questa sezione mostra come usare definizioni molto semplici (e relativamente rigide) per dimostrare come far funzionare l'ereditarietà. In queste definizioni, quando si crea un oggetto non è possibile specificare il valore di nessuna proprietà. L'oggetto creato avrà semplicemente i valori di default, che potranno essere cambiati in un secondo momento.

+ +

In una applicazione reale, probabilmente si vorranno definire dei costruttori che permettono di impostare i valori delle proprietà mentre si crea un oggetto (per maggiori informazioni si veda la sezione Costruttori più flessibili). Per adesso, queste semplici definizioni dimostrano come le proprietà vengono ereditate.

+ +

Le seguenti definizioni Java e JavaScript di Employee sono simili. L'unica differenza è che in Java si ha la necessità di specificare il tipo di ogni proprietà (questo è dovuto al fatto che Java è un linguaggio fortemente tipizzato mentre JavaScript è un linguaggio a tipizzazione dinamica.

+ +
+

JavaScript

+ +
function Employee() {
+  this.name = "";
+  this.dept = "general";
+}
+
+ +

Java

+ +
public class Employee {
+   public String name = "";
+   public String dept = "general";
+}
+
+
+ +

Le definizioni di Manager e WorkerBee mostrano la differenza nel modo di specificare l'oggetto seguente che si trova più in alto nella catena di ereditarietà. In JavaScript si aggiunge un'istanza prototipo come valore della proprietà prototype della funzione costrutore. È possibile farlo in qualsiasi momento dopo aver definito il costruttore. In Java, si specifica la superclasse all'interno della definizione della classe. Non è possibile cambiare la superclasse all'esterno della definizione.

+ +
+

JavaScript

+ +
function Manager() {
+  Employee.call(this);
+  this.reports = [];
+}
+Manager.prototype = Object.create(Employee.prototype);
+
+function WorkerBee() {
+  Employee.call(this);
+  this.projects = [];
+}
+WorkerBee.prototype = Object.create(Employee.prototype);
+
+ +

Java

+ +
public class Manager extends Employee {
+   public Employee[] reports = new Employee[0];
+}
+
+
+
+public class WorkerBee extends Employee {
+   public String[] projects = new String[0];
+}
+
+
+
+
+ +

Le definizioni di Engineer e SalesPerson creano oggetti che discendono da  WorkerBee, e quindi da Employee. Un oggetto di questo tipo ha le proprietà di tutti gli oggetti che si trovano sopra di esso nella catena. Inoltre, queste definizioni sovrascrivono il valore ereditato delle proprietà  dept con nuovi valori specifici per questi oggetti.

+ +
+

JavaScript

+ +
function SalesPerson() {
+   WorkerBee.call(this);
+   this.dept = "sales";
+   this.quota = 100;
+}
+SalesPerson.prototype = Object.create(WorkerBee.prototype);
+
+function Engineer() {
+   WorkerBee.call(this);
+   this.dept = "engineering";
+   this.machine = "";
+}
+Engineer.prototype = Object.create(WorkerBee.prototype);
+
+ +

Java

+ +
public class SalesPerson extends WorkerBee {
+   public String dept = "sales";
+   public double quota = 100.0;
+}
+
+
+public class Engineer extends WorkerBee {
+   public String machine;
+   public String dept = "engineering";
+   public String machine = "";
+}
+
+
+
+ +

Usando queste definizioni è possibile creare istanze di questi oggetti che ricevono i valori di default delle loro proprietà. La figura seguente illustra l'utilizzo di queste definizioni JavaScript per creare nuovi oggetti e mostra i valori delle diverse proprietà per questi nuovi oggetti.

+ +
+

Nota: Il termine istanza ha uno specifico significato tecnico nei linguaggi basati su classi. In questi linguaggi, un'istanza è una singola istanziazione di una classe ed è fondamentalmente differente dala classe. In JavaScript, "istanza" non ha questo significato tecnico perché JavaScript non ha questa differenza tra classi e istanze. Tuttavia, parlando di JavaScript, "istanza" può essere usato in modo informale per riferirsi a un oggetto creato usando una particolare funzione costruttore. Quindi, in questo esempio, è possibile dire che jane è un'istanza di Engineer. Allo stesso modo, sebbene i termini genitore  (parent), figlio (child), antenato (ancestor) e discendente (descendant) non hanno un significato conenzionale in JavaScript, possono essere usati in modo informale per riferirsi a oggetti che si trovano più o meno in alto nella catena dei prototipi.

+
+ +

Creazione di oggetti con definizioni semplici

+ +
+

Gerarchia degli oggetti

+ +

La gerarchia seguente è creata usando il codice sulla destra.

+ +

+ +

 

+ +

singoli oggetti

+ +
var jim = new Employee;
+// jim.name is ''
+// jim.dept is 'general'
+
+var sally = new Manager;
+// sally.name is ''
+// sally.dept is 'general'
+// sally.reports is []
+
+var mark = new WorkerBee;
+// mark.name is ''
+// mark.dept is 'general'
+// mark.projects is []
+
+var fred = new SalesPerson;
+// fred.name is ''
+// fred.dept is 'sales'
+// fred.projects is []
+// fred.quota is 100
+
+var jane = new Engineer;
+// jane.name is ''
+// jane.dept is 'engineering'
+// jane.projects is []
+// jane.machine is ''
+
+
+ +

Proprietà degli oggetti

+ +

Questa sezione spiega come gli oggetti ereditano le proprietà da altri oggetti presenti nella catena dei prototipi e cosa succede quando viene aggiunta una proprietà in fase di esecuzione.

+ +

Ereditare le proprietà

+ +

Supponiamo di creare un nuovo oggetto WorkerBee chiamato mark con l'istruzione seguente:

+ +
var mark = new WorkerBee;
+
+ +

Quando JavaScript vede l'operatore new, crea un nuovo oggeto generico e lo passa come valore della parola chiave this nella funzione costruttore WorkerBee. La funzione costruttore imposta esplicitamente il valore della proprietà projects e implicitamente il valore della proprietà interna __proto__ uguale al valore WorkerBee.prototype. (Il nome di questa proprietà ha due underscores iniziali e due finali). La proprietà __proto__ determina la catena di prototipi usata per restituire i valori delle proprietà. Una volta che queste proprietà sono impostate, JavaScript restituisce il nuovo oggetto e l'istruzione di assegnazione imposta la variabile mark per questo oggetto.

+ +

Questo processo non inserisce esplicitamente valori nell'oggetto mark (valori locali) per le proprietà che l'oggetto eredita dalla catena dei prototipi. Quando si richiede un valore di una proprietà, JavaScript prima controlla se il valore è presente nell'oggetto. Se c'è, viene restituito quel valore. Se il valore non è presente a livello locale, JavaScript controlla la catena dei prototipi (sfruttando la proprietà __proto__). Se un oggetto nella catena dei prototipi ha un valore per la proprietà, viene restituito. Se non viene trovata la proprietà, JavaScript risponde che l'oggetto non ha la proprietà cercata. In questo modo, l'oggetto mark ha le seguenti propietà con i rispettivi valori:

+ +
mark.name = "";
+mark.dept = "general";
+mark.projects = [];
+
+ +

L'oggetto mark eredita i valori per le proprietà name e dept dall'oggetto prototipo presente in mark.__proto__. Il costruttore WorkerBee assegna un valore locale per la proprietà projects. L'ereditarietà di proprietà e valori in JavaScript fnziona in questo modo. Alcune sottigliezze su questo processo sono trattate nella sezione Ereditare le proprietà (revisited).

+ +

Poiché questi costruttori non permettono di fornire valori specifici per una singola istanza, questa informazione è generica. I valori delle proprietà sono quelli di default condivisi da tutti i nuovi oggetti creati da WorkerBee. È oviamente possibile cambiare i valori di ognuna di queste proprietà. È quindi possibile assegnare informazioni specifice per mark nel modo seguente:

+ +
mark.name = "Doe, Mark";
+mark.dept = "admin";
+mark.projects = ["navigator"];
+ +

Aggiungere proprietà

+ +

In JavaScript, è possibile aggiungere proprietà a qualsiasi oggetto in fase di esecuzione. Non si è costretti ad usare solo le proprietà fornite dalla funzione costruttore. Per aggiungere una proprietà che sia specifica per un singolo oggetto, si deve assegnare il valore all'oggetto nel modo seguente::

+ +
mark.bonus = 3000;
+
+ +

Ora, l'oggetto markha una proprietà bonus, ma nessun altro WorkerBee ha questa proprietà.

+ +

Se si aggiunge una nuova proprietà a un oggetto che viene usato come prototipo per una funzione costruttore, la proprietà sarà aggiunta a tutti gli oggetti che ereditano le proprietà dal prototipo. Per esempio, è possibile aggiungere la proprietà specialty a tutti i dipendenti con l'istruzione seguente:

+ +
Employee.prototype.specialty = "none";
+
+ +

Non appena JavaScript esegue questa istruzione, anche l'oggetto mark avrà la proprietà specialty con il valore "none". La figura seguente mostra cosa succede qunado questa proprietà viene aggiunta al prototipo Employee e in seguito la si sovrascrive per il prototipo Engineer.

+ +


+ Aggiungere le proprietà

+ +

Costruttori più flessibili

+ +

Le funzioni costruttore mostrate finora non permettono di specificare i valori delle proprietà qunado viene creata un'istanza. Come in Java, è possibile fornire argomenti al costruttore per inizializzare i valori delle proprietà per le istanze. La figura seguente mostra un modo per farlo.

+ +


+ Specificare le proprietà in un costruttore, modo 1

+ +

La tabella seguente mostra le definizioni di questi oggetti in JavaScript e in Java.

+ +
+

JavaScript

+ +

Java

+
+ +
+
function Employee (name, dept) {
+  this.name = name || "";
+  this.dept = dept || "general";
+}
+
+ +

 

+ +

 

+ +

 

+ +

 

+ +
public class Employee {
+   public String name;
+   public String dept;
+   public Employee () {
+      this("", "general");
+   }
+   public Employee (String name) {
+      this(name, "general");
+   }
+   public Employee (String name, String dept) {
+      this.name = name;
+      this.dept = dept;
+   }
+}
+
+
+ +
+
function WorkerBee (projs) {
+
+ this.projects = projs || [];
+}
+WorkerBee.prototype = new Employee;
+
+ +

 

+ +

 

+ +
public class WorkerBee extends Employee {
+   public String[] projects;
+   public WorkerBee () {
+      this(new String[0]);
+   }
+   public WorkerBee (String[] projs) {
+      projects = projs;
+   }
+}
+
+
+ +
+
+function Engineer (mach) {
+   this.dept = "engineering";
+   this.machine = mach || "";
+}
+Engineer.prototype = new WorkerBee;
+
+ +

 

+ +

 

+ +
public class Engineer extends WorkerBee {
+   public String machine;
+   public Engineer () {
+      dept = "engineering";
+      machine = "";
+   }
+   public Engineer (String mach) {
+      dept = "engineering";
+      machine = mach;
+   }
+}
+
+
+ +

Queste definizioni JavaScript usano un linguaggio speciale per impostare i valori di default:

+ +
this.name = name || "";
+
+ +

In JavaScript l'operatore logico OR (||) valuta il suo primo argomento. Se questa espressione può essere convertita a true, l'operatore restituisce il primo argomento. Altrimenti l'operatore restituisce il valore del secondo argomento. Quindi, questa linea di codice verifica se name ha un valore utile per la proprietà name. Se ce l'ha, imposta this.name a questo valore. Altrimenti, imposta this.name a una stringa vuota. Questo capitolo usa questo linguaggio per brevità, comunque può disorientare a prima vista.

+ +
+

Nota: Potrebbe non funzionare come atteso se la funzione costruttore è chiamata con un argomento che converte a false (come ad esempio 0 (zero) o una stringa vuota ("")). In questo caso verrà scelto il valore di default.

+
+ +

Con queste definizioni, quando si crea un'istanza di un oggetto, è possibile specificare i valori per le proprietà definite localmente. Per creare un nuovo Engineer è possibile utilizzare l'espressione seguente:

+ +
var jane = new Engineer("belau");
+
+ +

Le proprietà di Jane sono ora:

+ +
jane.name == "";
+jane.dept == "engineering";
+jane.projects == [];
+jane.machine == "belau"
+
+ +

È da notare che con queste definizioni non è possibile specificare una valore iniziale per le proprietà ereditate, come ad esempio name. Se si desidera specificare un valore iniziale per una proprietà ereditata, in JavaScript è necessario aggiungere ulteriore codice alla funzione costruttore.

+ +

Finora, la funzione costruttore ha creato un oggetto generico e poi ha specificato proprietà locali e valori per il nuovo oggetto. È possibile fare in modo che il costruttore aggiunga più proprietà chiamando direttamente la funzione costruttore per un oggetto che si trova a un livello più alto nella catena dei prototipi. La figura seguente mostra queste nuove definizioni.

+ +


+ Specificare le proprietà in un costruttore, modo 2

+ +

Guardiamo nel dettaglio una di queste definizioni. Ecco la nuova definizione per il costruttore Engineer:

+ +
function Engineer (name, projs, mach) {
+  this.base = WorkerBee;
+  this.base(name, "engineering", projs);
+  this.machine = mach || "";
+}
+
+ +

Supponiamo di creare un nuovo oggetto Engineer nel modo seguente:

+ +
var jane = new Engineer("Doe, Jane", ["navigator", "javascript"], "belau");
+
+ +

JavaScript segue questa procedura:

+ +
    +
  1. L'operatore new crea un oggetto generico e imposta il valore Engineer.prototype per la sua proprietà __proto__.
  2. +
  3. L'operatore new passa il nuovo oggetto come valore della parola chiave this nella funzione costruttore Engineer.
  4. +
  5. Il costruttore crea una nuova proprietà per l'oggetto chiamata base e assegna il valore del costruttore WorkerBee alla proprietà base. Questo rende il costruttore WorkerBee un metode dell'oggetto Engineer. Il nome della proprietà base non è peculiare. È possibile usare qualsiasi nome per la proprietà; base è semplicemente evocativo dello scopo.
  6. +
  7. Il costruttore chiama il metodo base, passando come suoi argomenti due degli argomenti passati al costruttore ("Doe, Jane" e ["navigator", "javascript"]) e anche la stringa "engineering". Usando esplicitamente "engineering" nel costruttore indica che tutti gli oggetti Engineer hanno lo stesso valore per la proprietà dept ereditata, e questo valore sovrascrive il valore ereditato dal costruttore Employee.
  8. +
  9. Poiché base è un metodo di Engineer, all'interno della chiamata di base, JavaScript aggiunge la parola chiave this all'oggetto creato al passaggio 1. In questo modo, la funzione WorkerBee a sua volta passa gli argomenti "Doe, Jane" e "engineering" alla funzione costruttore Employee. Dopo l'esecuzione della funzione costruttore Employee, la funzione WorkerBee utilizza l'argomento rimanente per impostare la proprietà projects.
  10. +
  11. Dopo l'esecuzione del metodo base, il costruttore Engineer inizializza la proprietà machine dell'oggetto al valore "belau".
  12. +
  13. Dopo l'esecuzione del costruttore, JavaScript assegna il nuovo oggetto alla variabile jane.
  14. +
+ +

Avendo chiamato il costruttore WorkerBee dall'interno del costruttore Engineer, si potrebbe pensare di aver impostato in modo corretto l'ereditarietà per gli oggetti Engineer. Questo non è il caso. Chiamare il costruttore WorkerBee assicura che un oggetto Engineer venga creato con le proprietà specificate in tutte le funzioni costruttore che sono chiamate. Però, se in un secondo momento vengono aggiunte proprietà ai prototipi Employee o WorkerBee, queste proprietà non saranno ereditate dall'oggetto Engineer. Per esempio, se si considera il codice seguente:

+ +
function Engineer (name, projs, mach) {
+  this.base = WorkerBee;
+  this.base(name, "engineering", projs);
+  this.machine = mach || "";
+}
+var jane = new Engineer("Doe, Jane", ["navigator", "javascript"], "belau");
+Employee.prototype.specialty = "none";
+
+ +

L'oggetto jane non eredita la proprietà specialty. È comunque necessario impostare esplicitamente il prototipo per garantire l'ereditarietà dinamica. Se si considera invece l'esempio seguente:

+ +
function Engineer (name, projs, mach) {
+  this.base = WorkerBee;
+  this.base(name, "engineering", projs);
+  this.machine = mach || "";
+}
+Engineer.prototype = new WorkerBee;
+var jane = new Engineer("Doe, Jane", ["navigator", "javascript"], "belau");
+Employee.prototype.specialty = "none";
+
+ +

Adesso il valore per l'oggetto jane della proprietà specialty è "none".

+ +

Un altro modo per ereditare le proprietà è l'utilizzo dei metodi call() e apply(). Gli esempi sottostanti si equivalgono:

+ +
+
function Engineer (name, projs, mach) {
+  this.base = WorkerBee;
+  this.base(name, "engineering", projs);
+  this.machine = mach || "";
+}
+
+ +
function Engineer (name, projs, mach) {
+  WorkerBee.call(this, name, "engineering", projs);
+  this.machine = mach || "";
+}
+
+
+ +

L'utilizzo del metodo call() costituisce un'implementazione più pulita poiché la proprietà base non è più necessaria.

+ +

Ereditare le proprietà (revisited)

+ +

Le sezioni precedenti descrivono come i costruttori e i prototipi consentono di avere gerarchia ed ereditarietà in JavaScript. Questa sezione espone alcune sottiglienzze che non erano necessariamente evidenti nelle discussioni precedenti.

+ +

Valori locali vs. valori ereditati

+ +

Quando si accede a una proprietà di un oggetto, JavaScript esegue i seguenti passaggi, come descritto in precedenza in questo capitolo:

+ +
    +
  1. Verifica se il valore è presente a livello locale. Se c'è, restituisce quel valore.
  2. +
  3. Se non è presente, verifica la catena dei prototipi (usando la proprietà __proto__).
  4. +
  5. Se un oggetto nella catena dei prototipi ha un valore per la proprietà specificata, restituisce quel valore.
  6. +
  7. Se la proprietà non viene trovata, l'oggetto non ha la proprietà.
  8. +
+ +

Il risultato di questo processo dipende da come sono stati definiti gli elementi. L'esempio iniziale aveva queste definizioni:

+ +
function Employee () {
+  this.name = "";
+  this.dept = "general";
+}
+
+function WorkerBee () {
+  this.projects = [];
+}
+WorkerBee.prototype = new Employee;
+
+ +

Con queste definizioni, si supponga di creare amy come un'istanza di WorkerBee con la seguente istruzione:

+ +
var amy = new WorkerBee;
+
+ +

L'oggetto amy ha una proprietà locale, projects. I valori per le proprietà name e dept non sono specifici per amy e quindi derivano dalla proprietà __proto__ dell'oggetto amy. Quindi, amy ha i seguenti valori:

+ +
amy.name == "";
+amy.dept == "general";
+amy.projects == [];
+
+ +

Ora si supponga di cambiare il valore della proprietà name nel prototipo associato con Employee:

+ +
Employee.prototype.name = "Unknown"
+
+ +

Ci si potrebbe aspettare che il nuovo valore si propaghi a tutte le istanze di Employee. Invece, non lo fa.

+ +

Quando si crea qualsiasi istanza dell'oggetto Employee, questa istanza riceve un valore locale per la proprietà name (la stringa vuota). Questo significa che quando si imposta il prototipo WorkerBee creando un nuovo oggetto Employee, WorkerBee.prototype avrà un valore locale per la proprietà name. Quindi, quando JavaScript legge la proprietà name dell'oggetto amy (istanza di WorkerBee), trova in WorkerBee.prototype il valore locale di questa proprietà. Pertanto non continua a cercare nella catena salendo a Employee.prototype.

+ +

Se si vuole cambiare il valore di una proprietà di un oggetto in fase di esecuzione e si vuole che il nuovo valore venga ereditato da tutti i discendenti dell'oggetto, non è possibile definire la proprietà all'interno della funzione costruttore dell'oggetto. Invece, si aggiunge la proprietà al prototipo associato al costruttore. Per esempio, assumiamo di cambiare il codice precedente con quello che segue:

+ +
function Employee () {
+  this.dept = "general";    // Note that this.name (a local variable) does not appear here
+}
+Employee.prototype.name = "";    // A single copy
+
+function WorkerBee () {
+  this.projects = [];
+}
+WorkerBee.prototype = new Employee;
+
+var amy = new WorkerBee;
+
+Employee.prototype.name = "Unknown";
+
+ +

In questo caso, il valore della proprietà name di amy diventa "Unknown".

+ +

Come mostra questo esempio, se si vogliono avere i valori di default per le proprietà dell'oggetto e si vuole avere la possibilità di cambiare questi valori in fase di esecuzione, si devono impostare le proprietà nel prototipo del costruttore, e non direttamente nella funzione costruttore.

+ +

Determinazione delle relazioni tra istanze

+ +

In JavaScript la ricerca delle proprietà (property lookup) controlla prima tra le proprietà specifiche dell'oggetto e, se il nome della proprietà non viene trovato, controlla la proprietà speciale __proto__. Il processo, chiamato "ricerca nella catena dei prototipi" (lookup in the prototype chain), continua ricorsivamente .

+ +

Quando un oggetto viene costruito, la proprietà speciale __proto__ viene impostata al valore della proprietà prototype del costruttore. L'espressione new Foo() crea un oggetto con __proto__ == Foo.prototype. Di conseguenza, le modifiche alle proprietà di Foo.prototype alterano la ricerca delle proprietà per tutti gli oggetti che sono stati creati con new Foo().

+ +

Ogni oggetto ha una proprietà __proto__ (ad eccezione di Object); ogni funzione ha una proprietà prototype. Quindi gli oggetti possono essere correlati ad altri oggetti attraverso una 'ereditarietà prototipale' (prototypal inheritance). È possibile verificare l'ereditarietà confrontando la proprietà __proto__ di un oggetto con l'oggetto prototype di una funzione. JavaScript fornisce una scorciatoia: l'operatore instanceof confronta un oggetto con una funzione e restituisce true se l'oggetto eredita dal prototipo della funzione. Per esempio,

+ +
var f = new Foo();
+var isTrue = (f instanceof Foo);
+ +

Per un esempio più dettagliato, supponiamo di avere lo stesso gruppo di definizioni visto nella sezione For a more detailed example, suppose you have the same set of definitions shown in Ereditare le proprietà. Creiamo un oggetto Engineer nel modo seguente:

+ +
var chris = new Engineer("Pigman, Chris", ["jsd"], "fiji");
+
+ +

Per questo oggetto, tutti gli enunciati seguenti sono veri:

+ +
chris.__proto__ == Engineer.prototype;
+chris.__proto__.__proto__ == WorkerBee.prototype;
+chris.__proto__.__proto__.__proto__ == Employee.prototype;
+chris.__proto__.__proto__.__proto__.__proto__ == Object.prototype;
+chris.__proto__.__proto__.__proto__.__proto__.__proto__ == null;
+
+ +

Dato ciò, è possibile scrivere una funzione instanceOf come segue:

+ +
function instanceOf(object, constructor) {
+   object = object.__proto__;
+   while (object != null) {
+      if (object == constructor.prototype)
+         return true;
+      if (typeof object == 'xml') {
+        return constructor.prototype == XML.prototype;
+      }
+      object = object.__proto__;
+   }
+   return false;
+}
+
+ +
+

Nota: L'implementazione vista sopra verifica se l'oggetto è di tipo "xml" per ovviare a una stranezza nel modo in cui gli oggetti XML sono rappresentati nelle versioni recenti di JavaScript. Per i dettagli essenziali si veda il {{ bug(634150) }}.

+
+ +

Se si utilizza la funzione instanceOf definita in precedenza, queste espressioni sono vere:

+ +
instanceOf (chris, Engineer)
+instanceOf (chris, WorkerBee)
+instanceOf (chris, Employee)
+instanceOf (chris, Object)
+
+ +

Ma l'espressione seguente è falsa:

+ +
instanceOf (chris, SalesPerson)
+
+ +

Informazioni globali nei costruttori

+ +

Quando vengono creati dei costruttori, è necessario essere scrupolosi se si impostano informazioni globali all'interno del costruttore. Per esempio, se si vuole che un ID univoco venga assegnato automaticamente a ogni nuovo Employee si potrebbe usare la definizione seguente:

+ +
var idCounter = 1;
+
+function Employee (name, dept) {
+   this.name = name || "";
+   this.dept = dept || "general";
+   this.id = idCounter++;
+}
+
+ +

Con questa definizione, quando viene creato un nuovo Employee, il costruttore assegna l'ID seguente e incrementa il contatore globale (idCounter). Così, se l'istruzione successiva è la seguente, l'ID di victoria sarà 1, l'ID di harry sarà 2:

+ +
var victoria = new Employee("Pigbert, Victoria", "pubs")
+var harry = new Employee("Tschopik, Harry", "sales")
+
+ +

Questa a prima vista potrebbe sembrare la procedura corretta. Tuttavia, il contatore globale idCounter viene incrementato ogni volta che viene creato un oggetto Employee, per qualsiasi scopo. Se viene creata l'intera gerarchia di oggetti Employee mostrata in questo capitolo, il costruttore Employee viene chiamato ogni volta che si definisce un prototipo. Supponiamo di avere il codice seguente:

+ +
var idCounter = 1;
+
+function Employee (name, dept) {
+   this.name = name || "";
+   this.dept = dept || "general";
+   this.id = idCounter++;
+}
+
+function Manager (name, dept, reports) {...}
+Manager.prototype = new Employee;
+
+function WorkerBee (name, dept, projs) {...}
+WorkerBee.prototype = new Employee;
+
+function Engineer (name, projs, mach) {...}
+Engineer.prototype = new WorkerBee;
+
+function SalesPerson (name, projs, quota) {...}
+SalesPerson.prototype = new WorkerBee;
+
+var mac = new Engineer("Wood, Mac");
+
+ +

Si assuma inoltre che le definizioni omesse abbiano la proprietà base e chiamino il costruttore che si trova al livello superiore nella catena dei prototipi. In questo caso, nel momento in cui viene creato l'oggetto mac, il valore di mac.id sarà 5.

+ +

A seconda dell'applicazione, può essere più o meno importante che il valore del contatore sia stato incrementato queste volte aggiuntive. Se interessa il valore esatto di questo contatore, una soluzione possibile può prevedere l'uso del costruttore seguente al posto di quello visto in precedenza:

+ +
function Employee (name, dept) {
+   this.name = name || "";
+   this.dept = dept || "general";
+   if (name)
+      this.id = idCounter++;
+}
+
+ +

Quando viene creata un'istanza di Employee che deve essere usata come prototipo, non vengono forniti argomenti al costruttore. Usando questa definizione del costruttore, quando non vengono inseriti argomenti, il costruttore non assegna un valore all'ID e non aggiorna il contatore. Quindi, affinché a un oggetto Employee venga assegnato un ID, è necesario specificare un nome per il dipendente. In questo esempio, l'ID di mac sarà 1.

+ +

JavaScript non supporta l'ereditarietà multipla

+ +

Alcuni linguaggi ad oggetti ammettono l'ereditarietà multipla. Ossia, un oggetto può ereditare proprietà e valori da oggetti genitori non correlati. Javascript non supporta l'ereditarietà multipla.

+ +

L'eredità dei valori delle proprietà si ha in fase di esecuzione quando JavaScript cerca attraverso la catena dei prototipo di un oggetto per trovare un valore. Poiché un oggetto ha un unico prototipo associato, JavaScript non può ereditare dinamicamente da più di una catena di prototipi.

+ +

In JavaScript, è possibile che una funzione costruttore chiami al suo interno diverse funzioni costruttore. Questo dà l'illusione dell'ereditarietà multipla. Per esempio consideriamo le istruzioni seguenti:

+ +
function Hobbyist (hobby) {
+   this.hobby = hobby || "scuba";
+}
+
+function Engineer (name, projs, mach, hobby) {
+   this.base1 = WorkerBee;
+   this.base1(name, "engineering", projs);
+   this.base2 = Hobbyist;
+   this.base2(hobby);
+   this.machine = mach || "";
+}
+Engineer.prototype = new WorkerBee;
+
+var dennis = new Engineer("Doe, Dennis", ["collabra"], "hugo")
+
+ +

Assumiamo inoltre che la definizione di WorkerBee sia quella usata in precedenza in questo capitolo. In questo caso, l'oggetto dennis avrà queste proprietà:

+ +
dennis.name == "Doe, Dennis"
+dennis.dept == "engineering"
+dennis.projects == ["collabra"]
+dennis.machine == "hugo"
+dennis.hobby == "scuba"
+
+ +

Quindi dennis riceve la proprietà hobby dal costruttore Hobbyist. Però, se in seguito si aggiunge una proprietà al prototipo del costruttore Hobbyist:

+ +
Hobbyist.prototype.equipment = ["mask", "fins", "regulator", "bcd"]
+
+ +

L'oggetto dennis non erediterà questa nuova proprietà.

+ +
{{PreviousNext("Web/JavaScript/Guide/Working_with_Objects", "Web/JavaScript/Guide/Iterators_and_Generators")}}
diff --git a/files/it/web/javascript/guide/functions/index.html b/files/it/web/javascript/guide/functions/index.html new file mode 100644 index 0000000000..4aca8d5a7b --- /dev/null +++ b/files/it/web/javascript/guide/functions/index.html @@ -0,0 +1,646 @@ +--- +title: Funzioni +slug: Web/JavaScript/Guida/Functions +translation_of: Web/JavaScript/Guide/Functions +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Loops_and_iteration", "Web/JavaScript/Guide/Expressions_and_Operators")}}
+ +
 
+ +

Le funzioni sono tra i blocchi di programmazione fondamentali in JavaScript. Una funzione è una procedura JavaScript — un gruppo di istruzioni ( statement ) che esegue un compito o calcola un valore. Per usare una funzione, occorre definirla, all'interno dello scope dal quale la si invocherà.

+ +

Vedi anche l'esaustivo capitolo della guida di riferimento, che tratta delle funzioni JavaScript, per avere maggiori dettagli.

+ +

Definire una funzione

+ +

Dichiarazioni di funzione

+ +

Una definizione di funzione ( o dichiarazione di funzione, o istruzione di funzione ) consiste della parola chiave function, seguita da:

+ + + +

Per esempio, il codice seguente definisce una funzione semplice chiamata square:

+ +
function square(number) {
+  return number * number;
+}
+
+ +

La funzione square riceve un argomento, chiamato number. La funzione contiene una sola istruzione che dice di restituire ( return ) l'argomento della funzione ( number ) moltiplicato per se stesso. L'istruzione return specifica il valore restituito dalla funzione.

+ +
return number * number;
+
+ +

I parametri primitivi ( quale un numero ) vengono passati alla funzione come valore; il valore è passato alla funzione, ma se la funzione cambia il valore del parametro, questo cambiamento non si riflette globalmente, o nella funzione chiamante ( la funzione che, eventualmente, ha invocato la funzione in esecuzione ).

+ +

Se, invece, alla funzione viene passato un oggetto ( un valore non-primitivo, come, ad esempio, un Array oppure un oggetto definito dall'utente ) come parametro e la funzione modifica le proprietà dell'oggetto, quella modifica sarà visibile anche fuori dalla funzione, come si può vedere dal seguente esempio:

+ +
function myFunc(theObject) {
+  theObject.make = "Toyota";
+}
+
+var mycar = {make: "Honda", model: "Accord", year: 1998};
+var x, y;
+
+x = mycar.make; // x gets the value "Honda"
+
+myFunc(mycar);
+y = mycar.make; // y gets the value "Toyota"
+                // (the make property was changed by the function)
+
+ +

Espressioni di funzione

+ +

Mentre la dichiarazione di funzione di cui sopra è, da un punto di vista sintattico, un'istruzione, le funzioni possono anche essere create da un'espressione di funzione. Una funzione di questo tipo può anche essere anonima; vale a dire, non deve avere un nome. Per esempio, la funzione square potrebbe essere stata definita come:

+ +
var square = function(number) { return number * number };
+var x = square(4) // x gets the value 16
+ +

Tuttavia, è possibile assegnare un nome alla funzione anche con l'espressione di funzione e quel nome potrà essere utilizzato all'interno della funzione, per riferirsi alla funzione stessa, oppure in un debugger, per identificare la funzione all'interno dello stack:

+ +
var factorial = function fac(n) { return n<2 ? 1 : n*fac(n-1) };
+
+console.log(factorial(3));
+
+ +

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

+ +

Le espressioni di funzione sono utili quando si vuole passare una funzione ad un'altra funzione, come argomento. Il prossimo esempio mostra una funzione map che viene definita e poi invocata, con una funzione anonima come primo parametro:

+ +
function map(f,a) {
+  var result = [], // Create a new Array
+      i;
+  for (i = 0; i != a.length; i++)
+    result[i] = f(a[i]);
+  return result;
+}
+
+ +

Il seguente codice:

+ +
map(function(x) {return x * x * x}, [0, 1, 2, 5, 10]);
+
+ +

restituisce [0, 1, 8, 125, 1000].

+ +

In JavaScript, una funzione può essere definita in base ad una condizione. Per esempio, la definizione di funzione seguente definisce la funzione myFunc solo se num è uguale a 0 ( zero ):

+ +
var myFunc;
+if (num == 0){
+  myFunc = function(theObject) {
+    theObject.make = "Toyota"
+  }
+}
+ +

Per definire una funzione, inoltre, è possibile usare il costruttore Function, per creare funzioni da una stringa, in runtime, in modo simile a eval().

+ +

Un metodo è una funzione che è una proprietà di un oggetto. Leggi di più sugli oggetti e sui metodi in Working with objects.

+ +

Chiamare ( invocare ) una funzione

+ +

Definire una funzione non significa eseguirla. Definire una funzione significa semplicemente darle un nome e specificare cosa fare quando la funzione viene chiamata ( invocata ). Chiamare una funzione significa eseguire le azioni specificate, utilizzando i parametri indicati. Per esempio, se definiamo la funzione square, possiamo chiamarla o invocarla nel modo seguente:

+ +
square(5);
+
+ +

Questa istruzione chiama la funzione, inviandole un argomento, il numero 5. La funzione esegue le sue istruzioni e restituisce il valore 25.

+ +

Le funzioni devono essere in scope quando vengono chiamate, ma la dichiarazione di funzione può anche apparire sotto la chiamata, nel codice sorgente, come nell'esempio seguente:

+ +
console.log(square(5));
+/* ... */
+function square(n) { return n*n }
+
+ +

Lo scope di una funzione è la funzione nella quale è stata dichiarata, oppure l'intero programma se la dichiarazione è stata fatta al livello più alto, non annidata in alcun altro blocco di programmazione.

+ +
+

Nota: l'ultimo esempio funziona solo quando la funzione viene definita utilizzando la sintassi usata nell'esempio ( function funcName(){} ). Il codice seguente, invece, non funzionerà:

+
+ +
console.log(square(5));
+square = function (n) {
+  return n * n;
+}
+
+ +

Gli argomenti di una funzione non sono limitati alle stringhe testuali e ai numeri. È possibile passare anche interi oggetti ad una funzione. La funzione show_props() (definita in Working with objects) è un esempio di funzione che riceve, come argomento, un oggetto.

+ +

Una funzione può chiamare se stessa. Per esempio, ecco una funzione che calcola in modo ricorsivo i fattoriali ( molto simile alla funzione fac() vista poco prima in questa stessa pagina ):

+ +
function factorial(n){
+  if ((n == 0) || (n == 1))
+    return 1;
+  else
+    return (n * factorial(n - 1));
+}
+
+ +

A questo punto, è possibile calcolare i fattoriali dei cinque numeri seguenti:

+ +
var a, b, c, d, e;
+a = factorial(1); // a gets the value 1
+b = factorial(2); // b gets the value 2
+c = factorial(3); // c gets the value 6
+d = factorial(4); // d gets the value 24
+e = factorial(5); // e gets the value 120
+
+ +

Esistono altri metodi per chiamare una funzione. Ci sono casi in cui una funzione deve essere chiamata dinamicamente, oppure casi in cui il numero degli argomenti passati alla funzione varia, oppure casi in cui il contesto della chiamata di funzione deve essere impostato ad uno specifico oggetto, determinato in runtime ( tempo di esecuzione ). È chiaro che le funzioni sono, esse stesse, oggetti, e che questi oggetti hanno propri metodi (vedi l'oggetto Function). Uno di questi metodi, apply(), può essere usato a questo scopo.

+ +

Lo scope di una funzione

+ +

Alle variabili definite all'interno di una funzione non è possibile accedere dall'esterno della funzione, poichè la variabile è definita solo per lo scope della funzione ( scope: portata, ambiente, ambito in cui il nome della variabile può essere utilizzato per riferirsi ad essa ). Tuttavia, una funzione può accedere a tutte le variabili e a tutte le funzioni definite all'interno dello scope in cui è stata definita. In altre parole, una funzione definita nello scope globale può accedere a tutte le variabili definite nello scope globale. Una funzione definita all'interno di un'altra funzione può accedere anche a tutte le variabili definite nella funzione genitrice ( parent ), oltre che a tutte le altre variabili alle quali può accedere la funzione genitrice.

+ +
// Queste variabili sono definite nello scope globale
+
+var num1 = 20,
+    num2 = 3,
+    name = "Chamahk";
+
+// Questa funzione è definita nello scope globale
+
+function multiply() {
+    return num1 * num2;
+    }
+
+multiply(); // restituisce 60
+
+// Un esempio di funzione annidata
+function getScore () {
+  var num1 = 2,
+      num2 = 3;
+
+  function add() {
+    return name + " scored " + (num1 + num2);
+  }
+
+  return add();
+}
+
+getScore(); // restituisce "Chamahk scored 5"
+
+ +

Scope e lo stack della funzione

+ +

Ricorsione

+ +

Una funzione può chiamare se stessa. Esistono tre modi per una funzione di chiamare se stessa:

+ +
    +
  1. il nome della funzione
  2. +
  3. arguments.callee
  4. +
  5. una variabile in-scope che fa da riferimento alla funzione
  6. +
+ +

Per esempio, considerate la seguente definizione di funzione:

+ +
var foo = function bar() {
+   // statements go here
+};
+
+ +

All'interno del corpo della funzione, le tre seguenti istruzioni sono equivalenti:

+ +
    +
  1. bar()
  2. +
  3. arguments.callee()
  4. +
  5. foo()
  6. +
+ +

Una funzione che chiama se stessa viene detta funzione ricorsiva. In qualche modo, la ricorsione è analoga ad un loop. Entrambi eseguono lo stesso codice più volte ed entrambi richiedono una condizione (per evitare un loop infinito, o piuttosto, una ricorsione infinita, in questo caso). Per esempio, il loop seguente:

+ +
var x = 0;
+while (x < 10) { // "x < 10" is the loop condition
+   // do stuff
+   x++;
+}
+
+ +

può essere convertito in una funzione ricorsiva e in una chiamata a quella funzione:

+ +
function loop(x) {
+  if (x >= 10) // "x >= 10" is the exit condition (equivalent to "!(x < 10)")
+    return;
+  // do stuff
+  loop(x + 1); // the recursive call
+}
+loop(0);
+
+ +

Tuttavia, alcuni algoritmi non possono essere semplici loop iterativi. Per esempio, per avere tutti i nodi di una struttura ad albero (per esempio, il DOM) è molto più semplice usare la ricorsione:

+ +
function walkTree(node) {
+  if (node == null) //
+    return;
+  // do something with node
+  for (var i = 0; i < node.childNodes.length; i++) {
+    walkTree(node.childNodes[i]);
+  }
+}
+
+ +

Paragonato alla funzione loop, ciascuna chiamata ricorsiva, qui, esegue, a sua volta, molte chiamate ricorsive.

+ +

È possibile convertire qualsiasi algoritmo ricorsivo in un algoritmo non ricorsivo, ma spesso la logica è molto più complessa e per farlo è necessario utilizzare uno stack. In effetti, la ricorsione stessa usa uno stack: lo stack della funzione.

+ +

Un comportamento paragonabile allo stack può essere visto nell'esempio seguente:

+ +
function foo(i) {
+  if (i < 0)
+    return;
+  console.log('begin:' + i);
+  foo(i - 1);
+  console.log('end:' + i);
+}
+foo(3);
+
+// Output:
+
+// begin:3
+// begin:2
+// begin:1
+// begin:0
+// end:0
+// end:1
+// end:2
+// end:3
+ +

Funzioni annidate e chiusure

+ +

È possibile annidare una funzione all'interno di una funzione. La funzione annidata ( interna ) è privata, rispetto alla funzione che la contiene (outer o esterna). Essa forma anche una chiusura ( closure ). Una chiusura è un'espressione (normalmente, una funzione) che può avere variabili libere ( non locali ) legate ad un ambiente (ambiente che "chiude" l'espressione).

+ +

Dal momento in cui una funzione annidata è una chiusura, una funzione annidata può "ereditare" gli argomenti e le variabili della sua funzione contenitore (esterna o genitrice). In altre parole, la funzione interna contiene lo scope ( ambiente ) della funzione esterna.

+ +

Per riepilogare:

+ + + + + +

Ecco un esempio di funzione annidata:

+ +
function addSquares(a,b) {
+  function square(x) {
+    return x * x;
+  }
+  return square(a) + square(b);
+}
+a = addSquares(2,3); // restituisce 13
+b = addSquares(3,4); // restituisce 25
+c = addSquares(4,5); // restituisce 41
+
+ +

Dal momento in cui la funzione interna forma una chiusura, è possibile chiamare la funzione esterna e specificare gli argomenti per entrambe le funzioni, quella esterna e quella interna:

+ +
function outside(x) {
+  function inside(y) {
+    return x + y;
+  }
+  return inside;
+}
+fn_inside = outside(3); // Come dire: dammi una funzione che addizioni 3 a qualsiasi altro valore le venga passato
+result = fn_inside(5); // restituisce 8
+
+result1 = outside(3)(5); // restituisce 8
+
+ +

Persistenza delle variabili

+ +

Da notare come x venga preservata anche all'uscita da inside. Una chiusura deve preservare argomenti e variabili in tutti gli scope ai quali è riferita. Poichè ogni chiamata potrebbe trasportare argomenti differenti, per ogni chiamata alla funzione outside viene creata una nuova chiusura. La memoria può essere liberata solo quando inside non è più accessibile.

+ +

Una chiusura non è differente da un riferimento ad un oggetto, ma è meno ovvia di quest'ultimo, perchè non richiede di impostare direttamente il riferimento e perchè non è possibile ispezionare l'oggetto al quale il riferimento punta.

+ +

Funzioni annidate multiple

+ +

Le funzioni possono essere annidate a più livelli. Per esempio, una funzione (A), può contenere una funzione (B), che può contenere, a sua volta, una funzione (C). Entrambe le funzioni B e C formano una chiusura, qui, così B può accedere ad A e C può accedere a B. Inoltre, visto che C può accedere a B che può accedere ad A, C può anche accedere ad A. Quindi, le chiusure possono contenere più scope; ciascuna chiusura contiene lo scope delle funzioni che la contengono. Questo meccanismo è chiamato scope chaining ( catena di scope ). (Perchè è chiamata "catena" sarà chiaro tra poco.)

+ +

Considerate l'esempio seguente:

+ +
function A(x) {
+  function B(y) {
+    function C(z) {
+      console.log(x + y + z);
+    }
+    C(3);
+  }
+  B(2);
+}
+A(1); // logs 6 (1 + 2 + 3)
+
+ +

In questo esempio, C accede alla variabile y di B e alla x di A. Questo accade perchè:

+ +
    +
  1. B forma una chiusura che include A: quindi, B può accedere agli argomenti ed alle variabili di A.
  2. +
  3. C forma una chiusura che include B.
  4. +
  5. Poichè la chiusura di B include A, la chiusura di C include A; C può accedere agli argomenti ed alle variabili sia di B che di A. In altre parole, C unisce in una catena gli scope di B ed A in quell'ordine.
  6. +
+ +

Il contrario, tuttavia, non è vero. A non può accedere a C, perchè A non può accedere ad alcun argomento o variabile di B, di cui C è una variabile. Quindi, C resta privata solo a  B.

+ +

Conflitti tra nomi

+ +

Quando due argomenti o variabili, all'interno degli scope di una chiusura hanno lo stesso nome, nasce un conflitto tra nomi. Gli scope più interni hanno la precedenza, così lo scope più annidato ha la precedenza più elevata, mentre lo scope più esterno ha la precedenza più bassa. Questa è la catena degli scope. Il primo della catena è lo scope più annidato, mentre l'ultimo è lo scope più esterno. Vediamo il seguente esempio:

+ +
function outside() {
+  var x = 10;
+  function inside(x) {
+    return x;
+  }
+  return inside;
+}
+result = outside()(20); // returns 20 instead of 10
+ +

Il conflitto tra nomi avviene con l'istruzione return x ed è tra il nome del parametro x di inside ed il nome della variabile x di outside. La catena di scope qui è {inside, outside, global object}. Quindi, la x di inside ha la precedenza sulla x di outside: il valore restituito, alla fine, sarà 20 ( la x di inside ) e non 10 ( la x di  outside ).

+ +

Closure

+ +

Le closure sono uno dei meccanismi più potenti di JavaScript. JavaScript permette l'annidamento di funzioni e riconosce alla funzione interna il pieno accesso a tutte le variabili e a tutte le funzioni definite nella funzione esterna ( e a tutte le altre variabili e funzioni cui la funzione esterna ha accesso ). Tuttavia, la funzione esterna non ha accesso alle variabili ed alle funzioni definite nella funzione interna. Questo offre una certa protezione alle variabili della funzione interna. Inoltre, dal momento in cui la funzione interna ha accesso allo scope della funzione esterna, le variabili e le funzioni definite nella funzione esterna sopravviveranno alla funzione esterna stessa, se la funzione interna fa in modo di sopravvivere alla funzione esterna. Una closure viene creata quando la funzione interna viene resa disponibile in qualche modo agli scope esterni alla funzione esterna.

+ +
var pet = function(name) {   // La funzione esterna definisce una variabile di nome "name"
+  var getName = function() {
+    return name;             // La funzione interna ha accesso alla variabile "name" della funzione esterna
+  }
+  return getName;            // restituisce la funzione interna, esponendola, quindi, a scope esterni
+},
+myPet = pet("Vivie");
+
+myPet();                     // restituisce "Vivie"
+
+ +

Può essere molto più complicato del codice scritto sopra. Può essere restituito un oggetto contenente metodi per manipolare le variabili interne della funzione esterna.

+ +
var createPet = function(name) {
+  var sex;
+
+  return {
+    setName: function(newName) {
+      name = newName;
+    },
+
+    getName: function() {
+      return name;
+    },
+
+    getSex: function() {
+      return sex;
+    },
+
+    setSex: function(newSex) {
+      if(typeof newSex == "string" && (newSex.toLowerCase() == "male" || newSex.toLowerCase() == "female")) {
+        sex = newSex;
+      }
+    }
+  }
+}
+
+var pet = createPet("Vivie");
+pet.getName();                  // Vivie
+
+pet.setName("Oliver");
+pet.setSex("male");
+pet.getSex();                   // male
+pet.getName();                  // Oliver
+
+ +

Nel codice sopra, la variabile name della funzione esterna è accessibile alle funzioni interne e non c'è modo di accedere alle variabili interne, se non attraverso le funzioni interne. Le variabili interne della funzione interna agiscono come magazzino sicuro per le funzioni interne. Esse conservano i dati "persistenti" e sicuri che le funzioni interne utilizzano. Le funzioni non hanno nemmeno bisogno di vedersi assegnare ad una variabile o di avere un nome.

+ +
var getCode = (function(){
+  var secureCode = "0]Eal(eh&2";    // A code we do not want outsiders to be able to modify...
+
+  return function () {
+    return secureCode;
+  };
+})();
+
+getCode();    // Returns the secureCode
+
+ +

Ci sono, tuttavia, alcuni pericoli dai quali guardarsi, quando si utilizzano le closure. Se una funzione chiusa definisce una variabile che ha lo stesso nome di una variabile definita nello scope esterno, non sarà più possibile riferirsi alla variabile esterna.

+ +
var createPet = function(name) {  // Outer function defines a variable called "name"
+  return {
+    setName: function(name) {    // Enclosed function also defines a variable called "name"
+      name = name;               // ??? How do we access the "name" defined by the outer function ???
+    }
+  }
+}
+
+ +

È davvero  complicato usare la variabile magica this nelle closure. La variabile this è da usarsi con cautela, poichè ciò a cui this si riferisce dipende esclusivamente da dove è stata invocata la funzione, piuttosto che da dove è stata definita.

+ +

Usare l'oggetto arguments

+ +

Gli argomenti di una funzione vengono memorizzati in un oggetto, strutturato come un array. All'interno di una funzione, è possibile riferirsi agli argomenti passati alla funzione stessa nel modo seguente:

+ +
arguments[i]
+
+ +

dove i è il numero ordinale dell'argomento, a partire da zero. Così, il primo argomento passato ad una funzione sarà arguments[0]. Il numero totale degli argomenti è dato da arguments.length.

+ +

Usando l'oggetto arguments, è possibile chiamare una funzione con più argomenti di quanti ne possa formalmente accettare. Questo è spesso utile se non si sa in anticipo quanti argomenti verranno passati alla funzione. Si può usare l'attributo  arguments.length per determinare il numero degli argomenti realmente passati alla funzione, per poi accedere a ciascuno di essi usando l'oggetto arguments.

+ +

Prendiamo, per esempio, una funzione che unisca più stringhe. Il solo argomento formale previsto per la funzione è una stringa che specifica i caratteri da usare per separare le singole voci. La funzione viene definita così:

+ +
function myConcat(separator) {
+   var result = "", // initialize list
+       i;
+   // iterate through arguments
+   for (i = 1; i < arguments.length; i++) {
+      result += arguments[i] + separator;
+   }
+   return result;
+}
+
+ +

È possibile passare una quantità qualsiasi di argomenti alla funzione e la funzione comporrà una stringa testuale contenente tutti gli argomenti passati:

+ +
// returns "red, orange, blue, "
+myConcat(", ", "red", "orange", "blue");
+
+// returns "elephant; giraffe; lion; cheetah; "
+myConcat("; ", "elephant", "giraffe", "lion", "cheetah");
+
+// returns "sage. basil. oregano. pepper. parsley. "
+myConcat(". ", "sage", "basil", "oregano", "pepper", "parsley");
+
+ +
+

Nota: La variabile arguments è simile ad un array (  "array-like" ), ma non è un array. È simile ad un array poichè ha un indice numerato ed una proprietà length. Tuttavia, non possiede tutti i metodi di manipolazione degli array.

+
+ +

Vedi l'oggetto Function nella JavaScript reference, per avere maggiori informazioni.

+ +

I parametri di una funzione

+ +

A partire da ECMAScript 6, esistono due nuovi tipi di parametri: i parametri di default e i parametri rest.

+ +

I parametri di default

+ +

In JavaScript, i parametri di una funzione hanno come valore di default undefined. Tuttavia, in alcune situazioni potrebbe essere utile impostare un diverso valore di default. In questo, possono aiutare i parametri di default.

+ +

In passato, la strategia comune per impostare i valori di default era quella di verificare i valori dei parametri, all'interno del corpo della funzione, ed assegnare loro un valore, nel caso fossero stati undefined. Se nell'esempio seguente non venisse passato, durante la chiamata, alcun valore per b, il suo valore sarebbe undefined, anche quando venisse valutata l'istruzione a*b, e la chiamata a multiply restituirebbe NaN ( Not a Number ). Tuttavia, questo valore viene definito nella seconda riga:

+ +
function multiply(a, b) {
+  b = typeof b !== 'undefined' ?  b : 1;
+
+  return a*b;
+}
+
+multiply(5); // 5
+
+ +

Con i parametri di deafult, la verifica all'interno del corpo della funzione non è più necessaria. Ora, è possibile mettere 1 come valore di default per b nella dichiarazione della funzione:

+ +
function multiply(a, b = 1) {
+  return a*b;
+}
+
+multiply(5); // 5
+ +

Per maggiori dettagli, vedi paremetri di default nella Javascript reference.

+ +

I parametri Rest

+ +

La sintassi dei rest parameter permette di rappresentare un indefinito numero di argomenti come un array. Nell'esempio, usiamo i parametri rest per rappresentare l'insieme degli argomenti composto dagli argomenti successivi al primo ( a partire dal secondo argomento fino alla fine ). Poi, moltiplichiamo ciascun argomento dell'insieme per il primo. Questo esempio utilizza una funzione a freccia, che verrà introdotta nella prossima sezione.

+ +
function multiply(multiplier, ...theArgs) {
+  return theArgs.map(x => multiplier * x);
+}
+
+var arr = multiply(2, 1, 2, 3);
+console.log(arr); // [2, 4, 6]
+ +

Le funzioni a freccia

+ +

Una espressione di funzione a freccia ( nota anche come fat arrow function ) ha una sintassi più stringata rispetto alle espressioni di funzione e forza, lessicalmente, il valore di this. Le funzioni a freccia sono sempre anonime. Vedi anche il post di hacks.mozilla.org: "ES6 In Depth: Arrow functions".

+ +

Sono due i fattori che influenzarono l'introduzione delle funzioni a freccia: la brevità delle funzioni ed il this lessicale.

+ +

Funzioni più brevi

+ +

In alcuni modelli funzionali, funzioni più brevi sono le benvenute. Paragoniamo le due istruzioni seguenti:

+ +
var a = [
+  "Hydrogen",
+  "Helium",
+  "Lithium",
+  "Beryl­lium"
+];
+
+var a2 = a.map(function(s){ return s.length });
+var a3 = a.map( s => s.length );
+ +

Il this lessicale

+ +

Until arrow functions, every new function defined its own this value (a new object in case of a constructor, undefined in strict mode function calls, the context object if the function is called as an "object method", etc.). This proved to be annoying with an object-oriented style of programming.

+ +
function Person() {
+  // The Person() constructor defines `this` as itself.
+  this.age = 0;
+
+  setInterval(function growUp() {
+    // In nonstrict mode, the growUp() function defines `this`
+    // as the global object, which is different from the `this`
+    // defined by the Person() constructor.
+    this.age++;
+  }, 1000);
+}
+
+var p = new Person();
+ +

In ECMAScript 3/5, this issue was fixed by assigning the value in this to a variable that could be closed over.

+ +
function Person() {
+  var self = this; // Some choose `that` instead of `self`.
+                   // Choose one and be consistent.
+  self.age = 0;
+
+  setInterval(function growUp() {
+    // The callback refers to the `self` variable of which
+    // the value is the expected object.
+    self.age++;
+  }, 1000);
+}
+ +

Alternatively, a bound function could be created so that the proper this value would be passed to the growUp() function.

+ +

Arrow functions capture the this value of the enclosing context, so the following code works as expected.

+ +
function Person(){
+  this.age = 0;
+
+  setInterval(() => {
+    this.age++; // |this| properly refers to the person object
+  }, 1000);
+}
+
+var p = new Person();
+ +

Predefined functions

+ +

JavaScript has several top-level, built-in functions:

+ +
+
{{jsxref("Global_Objects/eval", "eval()")}}
+
+

The eval() method evaluates JavaScript code represented as a string.

+
+
{{jsxref("Global_Objects/uneval", "uneval()")}} {{non-standard_inline}}
+
+

The uneval() method creates a string representation of the source code of an {{jsxref("Object")}}.

+
+
{{jsxref("Global_Objects/isFinite", "isFinite()")}}
+
+

The global isFinite() function determines whether the passed value is a finite number. If needed, the parameter is first converted to a number.

+
+
{{jsxref("Global_Objects/isNaN", "isNaN()")}}
+
+

The isNaN() function determines whether a value is {{jsxref("Global_Objects/NaN", "NaN")}} or not. Note: coercion inside the isNaN function has interesting rules; you may alternatively want to use {{jsxref("Number.isNaN()")}}, as defined in ECMAScript 6, or you can use typeof to determine if the value is Not-A-Number.

+
+
{{jsxref("Global_Objects/parseFloat", "parseFloat()")}}
+
+

The parseFloat() function parses a string argument and returns a floating point number.

+
+
{{jsxref("Global_Objects/parseInt", "parseInt()")}}
+
+

The parseInt() function parses a string argument and returns an integer of the specified radix (the base in mathematical numeral systems).

+
+
{{jsxref("Global_Objects/decodeURI", "decodeURI()")}}
+
+

The decodeURI() function decodes a Uniform Resource Identifier (URI) previously created by {{jsxref("Global_Objects/encodeURI", "encodeURI")}} or by a similar routine.

+
+
{{jsxref("Global_Objects/decodeURIComponent", "decodeURIComponent()")}}
+
+

The decodeURIComponent() method decodes a Uniform Resource Identifier (URI) component previously created by {{jsxref("Global_Objects/encodeURIComponent", "encodeURIComponent")}} or by a similar routine.

+
+
{{jsxref("Global_Objects/encodeURI", "encodeURI()")}}
+
+

The encodeURI() method encodes a Uniform Resource Identifier (URI) by replacing each instance of certain characters by one, two, three, or four escape sequences representing the UTF-8 encoding of the character (will only be four escape sequences for characters composed of two "surrogate" characters).

+
+
{{jsxref("Global_Objects/encodeURIComponent", "encodeURIComponent()")}}
+
+

The encodeURIComponent() method encodes a Uniform Resource Identifier (URI) component by replacing each instance of certain characters by one, two, three, or four escape sequences representing the UTF-8 encoding of the character (will only be four escape sequences for characters composed of two "surrogate" characters).

+
+
{{jsxref("Global_Objects/escape", "escape()")}} {{deprecated_inline}}
+
+

The deprecated escape() method computes a new string in which certain characters have been replaced by a hexadecimal escape sequence. Use {{jsxref("Global_Objects/encodeURI", "encodeURI")}} or {{jsxref("Global_Objects/encodeURIComponent", "encodeURIComponent")}} instead.

+
+
{{jsxref("Global_Objects/unescape", "unescape()")}} {{deprecated_inline}}
+
+

The deprecated unescape() method computes a new string in which hexadecimal escape sequences are replaced with the character that it represents. The escape sequences might be introduced by a function like {{jsxref("Global_Objects/escape", "escape")}}. Because unescape() is deprecated, use {{jsxref("Global_Objects/decodeURI", "decodeURI()")}} or {{jsxref("Global_Objects/decodeURIComponent", "decodeURIComponent")}} instead.

+
+
+ +

{{PreviousNext("Web/JavaScript/Guide/Loops_and_iteration", "Web/JavaScript/Guide/Expressions_and_Operators")}}

diff --git a/files/it/web/javascript/guide/grammar_and_types/index.html b/files/it/web/javascript/guide/grammar_and_types/index.html new file mode 100644 index 0000000000..2a43d5230d --- /dev/null +++ b/files/it/web/javascript/guide/grammar_and_types/index.html @@ -0,0 +1,659 @@ +--- +title: Grammatica e tipi +slug: Web/JavaScript/Guida/Grammar_and_types +translation_of: Web/JavaScript/Guide/Grammar_and_types +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Introduction", "Web/JavaScript/Guide/Control_flow_and_error_handling")}}
+ +

Questo capitolo tratta la sintassi di base di JavaScript, le dichiarazioni di variabili, i tipi di dati e i letterali.

+ +

Nozioni di base

+ +

JavaScript mutua molta della sua sintassi da Java, ma è anche influenzato da Awk, Perl e Python.

+ +

JavaScript è sensibile al maiuscolo-minuscolo (case-sensitive) e usa l'insieme di caratteri Unicode.

+ +

In JavaScript, le istruzioni sono separate da punto e vigola (;). Spazi, tabulazioni e caratteri di a capo sono chiamati spazi bianchi. Il testo sorgente di uno script JavaScript viene analizzato da sinistra verso destra ed è convertito in una sequenza di elementi di input che sono: token, caratteri di controllo, terminatori di linea, commenti o spazi bianchi. ECMAScript definisce anche determinate parole chiave e letterali e ha delle regole per l'inserimento automatico dei punti e virgola (ASI) per chiudere le istruzioni. Tuttavia si raccomanda di aggiungere sempre un punto e virgola per terminare ogni istruzione, questo eviterà effetti collaterali. Per maggiori informazioni si veda il riferimento dettagliato riguardo la lexical grammar di JavaScript.

+ +

Commenti

+ +

La sintassi dei commenti è la stessa di quelli del C++ e di molti altri linguaggi:

+ +
// una linea di commento
+
+/* questo è un commento più lungo,
+   occupa più linee
+ */
+
+/* Però non puoi /* annidare i commenti */ SyntaxError */
+ +

Dichiarazioni

+ +

Ci sono tre tipi di dichiarazioni in JavaScript.

+ +
+
{{jsxref("Statements/var", "var")}}
+
Dichiarazione di una variabile, opzionalmente inizializzata ad un valore.
+
{{experimental_inline}} {{jsxref("Statements/let", "let")}}
+
Dichiarazione di una variabile locale con visibilità nel blocco, opzionalmente inizializzata ad un valore.
+
{{experimental_inline}} {{jsxref("Statements/const", "const")}}
+
Dichiarazione di una costante in sola lettura con un nome.
+
+ +

Variabili

+ +

Le variabili sono nomi simbolici da usare nelle applicazioni in luogo dei valori che rappresentano. I nomi delle variabili, chiamati  {{Glossary("Identifier", "identificatori")}}, devono seguire certe regole di scrittura.

+ +

Un identificatore JavaScript deve iniziare con una lettera, un trattino basso (_) o segno del dollaro ($), mentre i caratteri successivi possono anche essere le cifre (0-9). Siccome JavaScript è case-sensitive, le lettere includono i caratteri da "A" fino a "Z" (maiuscoli) e i caratteri da "a" fino a "z" (minuscoli).

+ +

Si possono usare anche le lettere ISO 8859-1 o Unicode come per esempio å e ü negli identificatori. Possono essere usate anche le sequenze di escape di Unicode come caratteri negli identificatori.

+ +

Alcuni esempi di nomi leciti sono Number_hits, temp99 e _name.

+ +

Dichiarazione di variabili

+ +

Una variabile può essere dichiarata in tre modi:

+ + + +

Valutazione delle variabili

+ +

Una variabile dichiarata usando le istruzioni  var o let senza nessun valore iniziale specificato ha il valore {{jsxref("undefined")}}.

+ +

Il tentativo di accedere ad una variabile non dichiarata o di accedere ad un identificatore dichiarato con l'istruzione let, prima di una sua inizializzazione, provocherà un'eccezione di {{jsxref("ReferenceError")}}:

+ +
var a;
+console.log("Il valore di a è " + a); // Scrive nel log "Il valore di a è undefined"
+
+console.log("Il valore di b è " + b); // Solleva una eccezione ReferenceError
+
+console.log("Il valore di c è " + c); // Scrive nel log "Il valore di c è undefined" 
+var c;
+
+console.log("Il valore di x è " + x); // Solleva una eccezione ReferenceError: x is not defined
+let x;
+ +

Si può usare undefined per determinare se una variabile ha un valore oppure no. Nel codice seguente alla variabile input non è stato assegnato un valore e la condizione dell'istruzione if è

+ +

valuta a true.

+ +
var input;
+if(input === undefined){
+  faiQuesto();
+} else {
+  faiQuello();
+}
+
+ +

Il valore undefined si comporta come false quando viene usato in un contesto booleano. Ad esempio il codice seguente esegue la funzione miaFunzione perché l'elemento di mioArray non è definito:

+ +
var mioArray = [];
+if (!mioArray[0]) miaFunzione();
+
+ +

Il valore undefined viene convertito in NaN quando viene usato in un contesto numerico.

+ +
var a;
+a + 2;  // Viene valutato a NaN
+ +

Quando viene valutata una variabile {{jsxref("null")}}, il valore null si comporta come 0 in un contesto numerico e false in un contesto booleano. Per esempio:

+ +
var n = null;
+console.log(n * 32); // Visualizzera nella console 0
+
+ +

Visibilità delle variabili

+ +

Quando una variabile viene dichiarata fuori da una qualsiasi funzione viene chiamata variabile globale, poiché è disponibile  in tutto il codice nel documento corrente. Quando invece la variabile viene dichiarata in una funzione viene chiamata variabile locale, perché è disponibile soltanto all'interno di quella funzione.

+ +

JavaScript prima di ECMAScript 2015 non aveva una visibilità a livello di blocco; piuttosto una variabile dichiarata all'interno di un blocco era locale alla funzione (o al contesto globale) in cui il blocco risiedeva. Per esempio il seguente codice scriverà nel log 5, perché la visibilità di x è la funzione (o il contesto globale) all'interno del quale x viene dichiarata e non il blocco, che in questo caso è l'istruzione if.

+ +
if (true) {
+  var x = 5;
+}
+console.log(x);  // 5
+
+ +

Il comportamento cambia quando si usa l'istruzione let introdotta in ECMAScript 2015.

+ +
if (true) {
+  let y = 5;
+}
+console.log(y);  // ReferenceError: y non è definita
+
+ +

Sollevamento delle variabili

+ +

Un'altra cosa inusuale riguardo le variabili in JavaScript è che si può fare riferimento ad una variabile dichiarata più avanti nello script senza causare una eccezione. Questo concetto è conosciuto come innalzamento (hoisting); le variabili in JavaScript sono in un certo senso "sollevate" o spostate all'inizio della definizione del corpo della funzione o dell'istruzione. Tuttavia le variabili che sono state sollevate ritornano il valore undefined. Dunque se viene usata (o si fa riferimento ad) una variabile prima che venga dichiarata questa ritornà undefined.

+ +
/**
+ * Esempio 1
+ */
+console.log(x === undefined); // visualizza "true" nel log
+var x = 3;
+
+/**
+ * Esempio 2
+ */
+var myvar = "mio valore";
+
+(function() {
+  console.log(myvar); // visualizza "undefined" nel log
+  var myvar = "valore locale";
+})();
+
+ +

L'esempio sopra sarà interpretato nello stesso modo di:

+ +
/**
+ * Esempio 1
+ */
+var x;
+console.log(x === undefined); // visualizza nel log "true"
+x = 3;
+
+/**
+ * Esempio 2
+ */
+var myvar = "mio valore";
+
+(function() {
+  var myvar;
+  console.log(myvar); // undefined
+  myvar = "valore locale";
+})();
+
+ +

Per via dell'innalzamento, tutte le istruzioni var in una funzione dovrebbero essere posizionate prima di ogni altra istruzione che vada a definire una funzione. Questa buona pratica incrementa la chiarezza del codice.

+ +

In ECMAScript 2015, let (const) non solleverà/sposterà la variabile all'inizio della dichiarazione del blocco, dunque un riferimento alla variabile nel blocco prima che questa venga dichiarata risulterà in un'eccezione di {{jsxref("ReferenceError")}}. La variabile si dice in una "zona temporale morta" ("temporal dead zone") dall'inizio del blocco fino alla a che non si incontri la sua dichiarazione.

+ +
console.log(x); // Solleverà un'eccezione ReferenceError
+let x = 3
+ +

Sollevamento delle Funzioni

+ +

Nel caso delle funzioni, solo la dichiarazione della funzione verrà spostata all'inizio. Se la funzione viene introdotta da un'espressione, in questo caso non verrà spostata.

+ +
/* Function declaration */
+
+foo(); // "bar"
+
+function foo() {
+  console.log("bar");
+}
+
+
+/* Function expression */
+
+baz(); // TypeError: baz is not a function
+
+var baz = function() {
+  console.log("bar2");
+};
+ +

Variabli globali

+ +

Le variabili globali sono in effetti proprietà dell'oggetto globale. Nelle pagine web l'oggetto globale è {{domxref("window")}} quindi è possibile impostare e accedere alle variabili globali usando la sintassi window.variabile.

+ +

Di conseguenza è possibile accedere a variabili globali dichiarate in una finestra o un frame da un'altra finestra o frame specificando il nome della finestra o del frame. Per esempio, se una variabile chiamata numeroDiTelefono è dichiarata in un documento, è possibile far riferimento a questa variabile dall'interno di un iframe come parent.numeroDiTelefono.

+ +

Costanti

+ +

È possibile creare una costante in sola lettura dandole un nome usando la parola chiave {{jsxref("Statements/const", "const")}}. La sintassi di un identificatore di costante è la stessa di un identificatore di variabile: deve iniziare con una lettera, trattino basso (_) o segno del dollaro ($) e può contenere caratteri alfabetici, numerici o trattini bassi.

+ +
const PI = 3.14;
+
+ +

Una costante non può cambiare il suo valore attraverso ulteriori assegnazioni o essere ridichiarata mentre lo script è in esecuzione. Deve anche essere inizializzata ad un valore.

+ +

Le regole di visibilità per le costanti sono le stesse di quelle per le variabil con visibilità al livello di blocco dichiarate con l'istruzione let. Se la parola chiave const viene omessa si assume che l'identificatore rappresenta una variabile.

+ +

Non è possibile dichiarare una costante con lo stesso nome di una funzione o di una variabile nello stesso spazio di visibilità. Per esempio:

+ +
// QUESTO CAUSERÀ UN ERRORE
+function f() {};
+const f = 5;
+
+// ANCHE QUESTO CAUSERÀ UN ERRORE
+function f() {
+  const g = 5;
+  var g;
+
+  //istruzioni
+}
+
+ +

Strutture dati e tipi

+ +

Tipi di dato

+ +

L'ultimo standard ECMAScript definisce sette tipi di dati:

+ + + +

Sebbene questi tipi di dati siano relativamente pochi questi permettono di eseguire funzioni utili nelle applicazioni. {{jsxref("Object", "Objects")}} e {{jsxref("Function", "functions")}} sono altri elementi fondamentali nel linguaggio. Si può pensatre agli oggetti come a contenitori con un nome per dei valori e alle funzioni come a procedure che l'applicazione può compiere.

+ +

Conversione dei tipi dei dati

+ +

JavaScript è un linguaggio con tipi assegnati dinamicamente. Questo significa che non si va a specificare il tipo di dato che una variabile conterrà quando viene dichiarata e anche che il tipo di un dato viene convertito automaticamente a seconda delle necessità durante l'esecuzione dello script. Così, per esempio, si può definire una variabile come segue:

+ +
var risposta = 42;
+
+ +

E più avanti è possibile assegnare alla stessa variabile un valore testo (stringa), per esempio:

+ +
risposta = "Grazie per tutti i pesci...";
+
+ +

Poiché in JavaScript i tipi si assegnano dinamicamente questa assegnazione non causerà un messaggio di errore.

+ +

Nelle espressioni che coinvolgono valori numerici e stringhe con l'operatore + JavaScript converte i valori numerici in stringhe. Per esempio si considerino le seguenti istruzioni:

+ +
x = "La risposta è " + 42 // "La risposta è 42"
+y = 42 + " è la risposta" // "42 è la risposta"
+
+ +

In istruzioni che coinvolgono altri operatori JavaScript non converte valori numerici in stringa. Per esempio:

+ +
"37" - 7 // 30
+"37" + 7 // "377"
+
+ +

Conversione delle stringhe in numeri

+ +

Nel caso in cui il valore che rappresenta un numero è memorizzato come stringa ci sono dei metodi per eseguire la conversione:

+ + + +

parseInt ritornerà soltanto numeri interi,  ha una utilità ridotta per i numeri decimali. In aggiunta è buona pratica nell'uso di parseInt includere il parametro base, questo parametro è usato per specificare quale sistema di numerazione deve essere usato.

+ +

Un metodo alternativo per recuperare un numero da un testo è di usare l'operatore + (più unario):

+ +
"1.1" + "1.1" = "1.11.1"
+(+"1.1") + (+"1.1") = 2.2
+// Note: le parentesi sono aggiunte per chiarezza, non sono richieste.
+ +

Letterali

+ +

I letterali sono usati per rappresentare i valori in JavaScript. Questi sono valori fissati, non variabili, che venvono letteralmente inseriti nello script. Questa sezione descrive i seguenti tipi di letterali:

+ + + +

Letterali di array

+ +

Un letterale di array è un elenco di zero o più espressioni ognuna delle quali rappresenta un elemento dell'array, inclusa in parentesi quadre ([]). Quando si crea un array usando un letterale l'array stesso viene inizializzato con i valori specificati come elementi, la sua lunghezza è impostata al numero di elementi specificati.

+ +

Il seguente esempio crea un array tipiDiCaffe con tre elementi e una lunghezza di tre:

+ +
var tipiDiCaffe = ["French Roast", "Colombian", "Kona"];
+
+ +
+

Nota: Un letterale di array è un tipo di inizializzatore di oggetto. Vedi Usando inizializzatori di Oggetti.

+
+ +

Se un array viene creato usando un letterale in uno script top-level, JavaScript interpreta l'array ogni volta che valuta l'espressione che contiene l'array letterale. In aggiunta l'array letterale usato in una funzione viene creato ogni volta che la funzione viene chiamata.

+ +

Gli array letterali sono anche oggetti Array. Si veda {{jsxref("Array")}} e Collezione indicizzata per i dettagli sugli oggetti Array.

+ +

Virgole aggiuntive negli array letterali

+ +

Non è obbligatorio specificare tutti gli elementi in un array letterale. Mettendo due virgole in fila l'array viene creato con il valore undefined per gli elementi non specificati. Il seguente esempio crea l'array pesce:

+ +
var pesce = ["Leone", , "Angelo"];
+
+ +

Questo array ha due elementi con un valore e un elemento vuoto (pesce[0] is "Leone", pesce[1] è undefined, e pesce[2] è "Angelo").

+ +

Inserendo una virgola in fondo alla lista degli elementi la virgola stessa verrà ignorata. Nel seguente esempio la lunghezza dell'array è tre, non c'è un miaLista[3]. Tutte le altre virgole nell'elenco indicano un elemento nuovo.

+ +
+

Nota: Le virgole in coda possono creare errori nelle versioni più vecchie dei browser ed è buona pratica rimuoverle.

+
+ +
var miaLista = ['casa', , 'scuola', ];
+
+ +

Nel seguente esempio la lunghezza dell'array è quattro e miaLista[0] e mialista[2] sono mancanti.

+ +
var miaLista = [ , 'casa', , 'scuola'];
+
+ +

Nel seguente esempio la lunghezza dell'array è quattro e mialista[1] e miaLista[3] sono mancanti. Soltanto l'ultima virgola viene ignorata.

+ +
var miaLista = ['casa', , 'scuola', , ];
+
+ +

Comprendere il comportamento delle virgole in più è importante per comprendere JavaScript come linguaggio, in ogni caso nella scrittura del codice: è buona norma dichiarare esplicitamente gli elementi mancanti come undefined, questo migliorerà la chiarezza e la manutenibilità del codice.

+ +

Letterali di booleani

+ +

Il tipo Boolean ha due valori letterali: true e false.

+ +

Non vanno confusi i valori primitivi Booleani true e false con i valori true e false dell'oggetto Boolean. L'oggetto Boolean è un involucro intorno al tipo primitivo Booleano. Vedi {{jsxref("Global_Objects/Boolean", "Boolean")}} per maggiori informazioni.

+ +

Letterali di numeri Interi

+ +

Gli interi possono essere rappresentati in decimale (base 10), esadecimale (base 16), ottale (base 8) e binario (base 2).

+ + + +

Alcuni esempi i di letterali di interi sono:

+ +
0, 117 and -345 (decimale, base 10)
+015, 0001 and -0o77 (ottale, base 8)
+0x1123, 0x00111 and -0xF1A7 (esadecimale, "hex" o base 16)
+0b11, 0b0011 and -0b11 (binario, base 2)
+
+ +

Per maggiori informazioni, vedi Numeric literals in the Lexical grammar reference.

+ +

Letterali di numeri in virgola-mobile

+ +

Un letterale per un numero in virgola mobile può avere le seguenti parti:

+ + + +

La parte esponente è una "e" o "E" seguita da un intero che può essere con segno (preceduto da "+" o "-"). Un numero in virgola mobile deve avere almeno una cifra e un punto oppure una "e" (o "E").

+ +

Più concisamente la sintassi è:

+ +
[(+|-)][cifre][.cifre][(E|e)[(+|-)]cifre]
+
+ +

Per esempio:

+ +
3.1415926
+-.123456789
+-3.1E+12
+.1e-23
+
+ +

Letterali di oggetti

+ +

Un letterale di un oggetto è una lista di zero o più coppie di nomi di proprietà e valori associati di un oggetto racchiusi in parentesi graffe ({}). Non andrebbe usato un letterale di un oggetto all'inizio di una istruzione, questo porterà ad un errore o non si comporterà come ci si aspetta perché { sarà interpretata come l'inizio di un blocco.

+ +

Quello seguente è un esempio di un letterale di un oggetto. Il primo elemento dell'oggetto automobile definisce un proprietà, miaAutomobile, e gli assegna il testo "Saturn"; il secondo elemento, la proprietà getAutomobile, è immediatamente assegnata al valore risultante dall'invocazione della funzione (tipiDiAutomobile("Honda")); il terzo elemento, la proprietà speciale, usa una variabile esistente (saldi).

+ +
var saldi = "Toyota";
+
+function tipiDiAutomobile(nome) {
+  if (nome === "Honda") {
+    return nome;
+  } else {
+    return "Spiacente, noi non vendiamo " + nome + ".";
+  }
+}
+
+var automobile = { miaAutomobile: "Saturn", getAutomobile: tipiDiAutomobile("Honda"), speciale: saldi };
+
+console.log(automobile.miaAutomobile);   // Saturn
+console.log(automobile.getAutomobile);  // Honda
+console.log(automobile.speciale); // Toyota
+
+ +

In aggiunta si possono usare letterali di tipo numerico o testo come nome di una proprietà o annidare un oggetto dentro un altro. Il seguente esempio usa queste opzioni.

+ +
var automobile = { molteAutomobili: {a: "Saab", "b": "Jeep"}, 7: "Mazda" };
+
+console.log(automobile.molteAutomobili.b); // Jeep
+console.log(automobile[7]); // Mazda
+
+ +

I nomi delle proprietà degli oggetti possono essere un testo qualsiasi, incluso il testo vuoto. Se il nome della proprietà non è un {{Glossary("Identifier","identifier")}} JavaScript valido o un numero dovrà essere racchiuso tra virgolette. I nomi di proprietà che non sono identificatori validi non possono neanche essere acceduti usando il punto (.), potranno però essere acceduti e impostati usando la notazione analoga a quella degli array ("[]").

+ +
var nomiDiProprietaInusuali = {
+  "": "Una stringa vuota",
+  "!": "Bang!"
+}
+console.log(nomiDiProprietaInusuali."");   // SyntaxError: Unexpected string
+console.log(nomiDiProprietaInusuali[""]);  // Una stringa vuota
+console.log(nomiDiProprietaInusuali.!);    // SyntaxError: Unexpected token !
+console.log(nomiDiProprietaInusuali["!"]); // Bang!
+ +

In ES2015, i letterali di oggetti sono estesi per supportare l'impostazione del prototipo al momento della costruzione, forme abbreviate per le assegnazioni tipo foo: foo, definizioni di metodi, eseguire chiamate a super e calcolare il nome di proprietà con espressioni. Nel'insieme queste aggiunte avvicinano i letterali di oggetti e le dichiarazioni delle classi permettendo quindi di beneficiare di alcune delle stesse comodità della progettazione orientata agli oggetti.

+ +
var obj = {
+    // __proto__
+    __proto__: theProtoObj,
+    // Abbreviazione per ‘handler: handler’
+    handler,
+    // Metodi
+    toString() {
+     // Super calls
+     return "d " + super.toString();
+    },
+    // Nomi di proprietà calcolati (dinamici)
+    [ 'prop_' + (() => 42)() ]: 42
+};
+ +

Nota che:

+ +
var foo = {a: "alpha", 2: "two"};
+console.log(foo.a);    // alpha
+console.log(foo[2]);   // two
+//console.log(foo.2);  // Error: missing ) after argument list
+//console.log(foo[a]); // Error: a is not defined
+console.log(foo["a"]); // alpha
+console.log(foo["2"]); // two
+
+ +

Letterali di RegExp

+ +

Un letterale di espressione regolare (RegExp) è un modello (pattern) racchiuso tra barre. il seguente è un esempio di un letterale di una espressione regolare.

+ +
var re = /ab+c/;
+ +

Letterali di stringhe

+ +

Un letterale di testo (stringa nel preguo del testo) è formato da zero o più caratteri racchiusi tra virgolette doppie  (") o singole (').  Una stringa deve essere delimitata da virgolette dello stesso tipo; cioè o entrambe singole o entrambe doppie. I seguenti sono esempi di leterali di testo:

+ +
"foo"
+'bar'
+"1234"
+"una linea \n altra linea"
+"prima dell'una"
+
+ +

È possibile chiamare qualsiasi metodo dell'oggetto String su una stringa —JavaScript converte automaticamente la stringa in un oggetto temporaneo di tipo String, chiama il metodo, poi elimina l'oggetto temporaneo. È anche possibile usare la proprietà String.length con una stringa letterale:

+ +
console.log("John's cat".length)
+// Stamperà il numero di simboli nel testo inclusi gli spazi.
+// In questo caso 10.
+
+ +

In ES2015 sono disponibili i letterali modello. I letterali modello sono racchiusi tra accenti gravi (` `)  (accento grave) anziché apici doppi o singoli. Le stringhe modello fornisco dello "zucchero sintattico" per la costruzione delle stringhe. È simile all'interpolazione delle stringhe di Perl, Python e altri. Opzionalmente, un'etichetta può essere aggiunta per permettere la personalizzazione nella costruzione della stringa, evitare gli attacchi per injection o costruire strutture dati di livello più alto dal contenuto di una stringa.

+ +
// Creazione di un letterale string di base
+`In JavaScript '\n' is a line-feed.`
+
+// Stringa multilinea
+`In JavaScript this is
+ not legal.`
+
+// Interpolazione di stringhe
+var name = "Bob", time = "today";
+`Hello ${name}, how are you ${time}?`
+
+// La costruzione di un prefisso di richiesta HTTP è usata per interpretare le sostituzioni e le costruzioni
+POST`http://foo.org/bar?a=${a}&b=${b}
+     Content-Type: application/json
+     X-Credentials: ${credentials}
+     { "foo": ${foo},
+       "bar": ${bar}}`(myOnReadyStateChangeHandler);
+ +

Si dovrebbero usare i letterali stringa a meno che non ci sia specifico bisogno di usare un oggetto String. Si veda {{jsxref("String")}} per dettagli sull'oggetto String.

+ +

Uso di caratteri speciali nelle stringhe

+ +

Oltre ai caratteri ordinari si possono includere anche dei caratteri speciali nelle stringhe come mostrato nel seguente esempio.

+ +
"prima linea \n seconda linea"
+
+ +

La seguente tabella elenca i caratteri speciali che possono essere usati nelle stringhe JavaScript.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Table: JavaScript caratteri speciali
CarattereSignificato
\0Byte null
\bBackspace
\fForm feed
\nNew line
\rCarriage return
\tTab
\vTab verticale
\'Apostrofo o virgoletta singola
\"Virgoletta doppia
\\Il carattere backslash
\XXXIl carattere con la codifica Latin-1 specificata da fino a tre caratteri XXX tra 0 e 377. Per esempio \251 è la sequenza ottale per il simbolo di copyright.
\xXXIl carattere con la codifica Latin-1 specificata da due cifre esadecimali XX comprese tra 00 e FF. Per esempio \xA9 è la sequenza ottale per il simbolo di copyright.
\uXXXXIl carattere Unicode specificato da quattro cifre esadecimali XXXX. Per esempio \u00A9 è la sequenza Unicode per il simbolo di copyright. Vedi Unicode escape sequences.
\u{XXXXX}Escape per Unicode code point. Per esempio \u{2F804} è la stessa cosa dell'esape semplice Unicode \uD87E\uDC04.
+ +

Caratteri a cui aggiungere il backslash (Escaping)

+ +

Per i caratteri non elencati nella tabella un backslash (\) prefisso viene ignorato, questo uso è deprecato e devrebbe essere evitato.

+ +

Le virgolette possono essere inserite in una stringa precedendole da un backslash. Questo è noto come escaping delle virgolette. Per esempio:

+ +
var quote = "Lui legge \"The Cremation of Sam McGee\" by R.W. Service.";
+console.log(quote);
+
+ +

Il risultato sarebbe:

+ +
Lui legge "The Cremation of Sam McGee" by R.W. Service.
+
+ +

Per includere un backslash in una stringa va fatto l'esape del carattere backslash. Per esempio, per assegnare il percorso c:\temp ad una stringa, usare il seguente:

+ +
var home = "c:\\temp";
+
+ +

Si può anche fare l'escape delle interruzioni di linea precedendole con un backslash. Sia il backslash che l'interruzione di linea saranno rimosse dal valore della stringa.

+ +
var str = "questa stringa \
+è spezzata \
+attraverso multiple\
+linee."
+console.log(str);   // questa stringa è spezzata attraverso multiple linee.
+
+ +

Sebbene JavaScript non abbia una sintassi tipo "heredoc", è possibile fare qualcosa di simile aggiungendo una sequenza di escape per "a capo" e facendo l'escape dell'a capo alla fine della linea:

+ +
var poem =
+"Roses are red,\n\
+Violets are blue.\n\
+I'm schizophrenic,\n\
+And so am I."
+
+ +

Ulteriori informazioni

+ +

Questo capitolo si concentra sulla sintassi di base per i tipi e le dichiarazioni. Per imparare di più riguardo i costrutti del linguaggio JavaScript vedi anche i seguenti capitoli in questa guida:

+ + + +

Nel prossimo capitolo, tratteremo i costrutti del controllo del flusso e la gestione degli errori.

+ +

{{PreviousNext("Web/JavaScript/Guide/Introduction", "Web/JavaScript/Guide/Control_flow_and_error_handling")}}

diff --git a/files/it/web/javascript/guide/index.html b/files/it/web/javascript/guide/index.html new file mode 100644 index 0000000000..ba956f21f2 --- /dev/null +++ b/files/it/web/javascript/guide/index.html @@ -0,0 +1,124 @@ +--- +title: JavaScript Guide +slug: Web/JavaScript/Guida +tags: + - AJAX + - JavaScript + - JavaScript_Guide + - NeedsTranslation + - TopicStub +translation_of: Web/JavaScript/Guide +--- +
{{jsSidebar("JavaScript Guide")}}
+ +

La Guida JavaScript mostra come utilizzare JavaScript e offre una panoramica del linguaggio. Se hai bisogno di informazioni esaustive su una sua funzione, dai un'occhiata alle reference JavaScript.

+ +

Capitoli

+ +

Questa guida è divisa in vari capitoli:

+ + + + + + + + + +

{{Next("Web/JavaScript/Guide/Introduction")}}

diff --git a/files/it/web/javascript/guide/introduction/index.html b/files/it/web/javascript/guide/introduction/index.html new file mode 100644 index 0000000000..3825ded91c --- /dev/null +++ b/files/it/web/javascript/guide/introduction/index.html @@ -0,0 +1,140 @@ +--- +title: Introduzione +slug: Web/JavaScript/Guida/Introduzione +tags: + - Guida + - JavaScript +translation_of: Web/JavaScript/Guide/Introduction +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide", "Web/JavaScript/Guide/Grammar_and_types")}}
+ +

Questo capitolo introduce JavaScript e discute alcuni dei suoi concetti fondamentali.

+ +

Che cosa dovresti già sapere

+ +

Questa guida parte dal presupposto che tu abbia già queste nozioni di base:

+ + + +

Dove trovare informazioni su JavaScript

+ +

La documentazione JavaScript su MDN comprende:

+ + + +

Se sei nuovo di JavaScript, inizia con gli articoli presenti in Capire il web e nella  Guida JavaScript. Quando avrai una chiara comprensione dei fondamentali, potrai usare il  Riferimento JavaScript per apprendere maggiori dettagli su singoli oggetti e parti del linguaggio.

+ +

Che cos'è JavaScript?

+ +

JavaScript è un linguaggio di scripting cross-platform e object-oriented. È un linguaggio piccolo e leggero. All interno di un ambiente ospite (ad esempio un web browser), JavaScript può essere connesso agli oggetti del suo ambiente per fornire controllo programmatico su di essi.

+ +

JavaScript contiene una libreria standard di oggetti come Array, Date e Math, ed una serie di elementi base del linguaggio come operatori, strutture di controllo e dichiarazioni. La base di JavaScript può essere estesa per una varietà di scopi fornendogli oggetti aggiuntivi; ad esempio:

+ + + +

JavaScript e Java

+ +

JavaScript e Java sono simili per certi aspetti, ma fondamentalmente diversi per altri. Il linguaggio JavaScript assomiglia a Java ma non ha la tipizzazione statica ed il controllo forte dei tipi di Java. JavaScript segue larga parte della sintassi delle espressioni di Java, la convenzione sui nomi ed i principali costrutti di controllo di flusso, e questa è la ragione per cui è stato rinominato da LiveScript a JavaScript.
+ A differenza del sistema di classi costruito dalle dichiarazione a tempo di compilazione di Java, JavaScript supporta un sistema runtime basato su un piccolo numero di tipi di dato che rappresentano valori Booleani, numerici e di tipo stringa. JavaScript dispone di un modello ad oggetti basato su prototype al posto del più comune modello ad oggetti basato su classi. Il modello prototype-based fornisce ereditarietà dinamica; che significa che ciò che viene ereditato può variare per singoli oggetti. JavaScript inoltre supporta funzioni senza speciali requisiti dichiarativi. Le funzioni possono essere proprietà di oggetti, eseguite come metodi debolmente tipizzati.

+ +

JavaScript è un linguaggio con un formalismo molto libero se confrontato a Java. Non è necessario dichiarare tutte le variabili, classi e metodi. Non ci si deve preoccupare se i metodi sono public, privare e protected, e non è necessario implementare interfacce. Variabili, parametri e valori di ritorno delle funzioni non sono tipizzati in modo esplicito.

+ +

Java è un linguaggio di programmazione basato su classi progettato per essere veloce e con un controllo dei tipi rigoroso. Con controllo dei tipi rigoroso si intende per esempio, che non è possibile forzare un intero Java in un riferimento ad oggetto o accedere alla memoria privata corrompendo i bytecodes Java. Il modello basato sulle classi di Java significa che i programmi sono composti esclusivamente da classi con i propri metodi. L'ereditarietà delle classi di Java e la tipizzazione forte di solito richiedono gerarchie di oggetti strettamente definite. Questi requisiti rendono la programmazione di Java più complessa rispetto alla programmazione di JavaScript.

+ +

D'altra parte, JavaScript si ispira ad una linea di linguaggi più piccoli, tipizzati dinamicamente come HyperTalk e dBASE. Questi linguaggi di scripting offrono strumenti di programmazione ad un pubblico più vasto grazie alla loro sintassi più facile, alle funzionalità specializzate predefinite nel linguaggio, ed ai minimi requisiti per la creazione di oggetti.

+ + + + + + + + + + + + + + + + + + + + + + + +
JavaScript confrontato con Java
JavaScriptJava
+

Orientato ad oggetti. Non c'è distinzione tra tipi di oggetti. Ereditarietà con il meccanismo dei prototype e le proprietà ed i metodi possono essere aggiunti ad ogni oggetto dinamicamente.

+
+

Basato su classi. Gli oggetti vengono distinti in classi ed istanze con tutta l'ereditarietà costruita con lagerarchia delle classi. Classi ed istanze non possono avere proprietà o metodi aggiunti dinamicamente.

+
Le variabili ed i tipi non sono dichiarati (tipizzazione dinamica).Le variabili ed i tipi di dato devono essere dichiarati (tipizzazione statica).
Non si può scrivere automaticamente suk disco fisso.Si può scrivere automaticamente su disco fisso.
+ +

Per maggiori informazioni sulle differenze tra JavaScript e Java, vedi il capitolo Dettagli sul modello ad oggetti.

+ +

JavaScript e le specifiche ECMAScript

+ +

JavaScript è standardizzato da Ecma International — l'associazione Europea per la standardizzazione dei sisteni di comunicazione ed informazione (ECMA è l'acronimo di European Computer Manufacturers Association) per distribuire linguaggio di programmazione standardizzato ed internazionale basato su JavaScript. Questa versione standardizzata di JavaScript, chiamata ECMAScript, si comporta alla stesso modo in tutte le applicazioni che supportano lo standard. Le aziende possono usare il linguaggo standard aperto per svilupare le proprie implementazioni di JavaScript. Lo standard ECMAScript è documentato nelle specifiche ECMA-262. Consulta Novità in JavaScript per conoscere di più sulle differenti versioni di JavaScript e delle edizioni delle specifiche ECMAScript.

+ +

Lo standard ECMA-262 è anche approvato da ISO (International Organization for Standardization) come ISO-16262. Si possono trovare le specifiche nel sito Ecma internazionale. Le specifiche ECMAScript non descrivono il Document Object Model (DOM), che viene standardizzato dal World Wide Web Consortium (W3C). Il DOM definisce il modo in cui gli oggetti di un documento HTML vengono esposti al tuo script. Per farti un'idea migliore sulle differenti tecnologie che si usano quando si programma con JavaScript, consulta l'articolo Panoramicha delle tecnologie JavaScript.

+ +

Documentazione JavaScript a confronto con le specifiche ECMAScript

+ +

Le specifiche ECMAScript sono una serie di requisiti per implementare ECMAScript; sono utili per chi desidera implementare funzionalità compatibili con lo standard del linguaggio nella propria implementazione di ECMAScript (come SpiderMonkey in Firefox, o v8 in Chrome).

+ +

La documentazione ECMAScript non è indirizzata ad aiutare i programmatori di script; usa la documentazione di JavaScript per informazioni su come scrivere script.

+ +

Le specifiche ECMAScript usano terminologie e sintassi che possono risultare non  familiari ai programmatori JavaScript Sebbene la descrizione del linguaggio possa essere diversa in ECMAScript, il linguaggio in se rimane lo stesso. JavaScript supporta tutte le funzionalità descritte nelle specifiche ECMAScript.

+ +

La documentazione JavaScript descrive aspetti del linguaggio che sono appropriati per il programmatore JavaScript.

+ +

Iniziare con JavaScript

+ +

Iniziare con JavaScript è facile: la sola cosa che serve è un Web browser moderno. Questa guida include alcune funzionalità di JavaScript che sono attualmente disponibili solo nell'ultima versione di Firefox, per questo raccomandiamo di usare la versione più recente di Firefox.

+ +

In Firefox sono presenti due strumenti che sono utili per sperimentare con JavaScript: la Console Web ed il Blocco per gli appunti.

+ +

La Console Web

+ +

La Console Web espone informazioni sulla pagina Web attualmente caricata, ed include una command line che si può usare per eseguire espressioni nella pagina corrente.

+ +

Per aprire la Console Web (Ctrl+Shift+K), scegli "Console web" dal menu "Sviluppo web", che si trova nel menu "Strumenti" di Firefox. Essa appare sotto la finestra del browser. Alla fine della console è presente la linea di comando che si può usare per inserire comandi JavaScript ed il risultato compare nel pannello soprastante:

+ +

+ +

Blocco per gli appunti

+ +

La Console Web è magnifica per eseguire singole linee di JavaScript, ma sebbene si possano eseguire linee multiple, non è molto comoda per questo e non è possibile salvare i propri esempi di codice con la Console Web. Quindi per esempi più complessi di codice il Blocco per gli appunti è uno strumento migliore.

+ +

Per aprire il Blocco per gli appunti (Shift+F4), scegli "Blocco per gli appunti" dal menu "Sviluppo web", che si trova nel menu "Strumenti" di Firefox. Si apre in una finestra separata ed un editor che puoi usare per scrivere ed eseguire JavaScript nel browser. Si possono anche salvare scripts nel disco e caricare scripts salvati.

+ +

+ +

Hello world

+ +

Per iniziare a scrivere programmi JavaScript, apri il Blocco per gli appunti e scrivi il tuo primo codice "Hello world" JavaScript:

+ +
function greetMe(yourName) {
+  alert("Hello " + yourName);
+}
+
+greetMe("World");
+
+ +

Seleziona il codice nel blocco e premi Ctrl+R per vedere il risultato nel browser!

+ +

Nelle prossime pagine, questa guida ti itrodurra alla sintassi di JavaScript ed alle caratteristiche del linguaggio, in questo modo sarai in grado di scrivere applicazioni più complesse.

+ +

{{PreviousNext("Web/JavaScript/Guide", "Web/JavaScript/Guide/Grammar_and_types")}}

diff --git a/files/it/web/javascript/guide/iterators_and_generators/index.html b/files/it/web/javascript/guide/iterators_and_generators/index.html new file mode 100644 index 0000000000..49b220cdd1 --- /dev/null +++ b/files/it/web/javascript/guide/iterators_and_generators/index.html @@ -0,0 +1,162 @@ +--- +title: Iteratori e generatori +slug: Web/JavaScript/Guida/Iteratori_e_generatori +translation_of: Web/JavaScript/Guide/Iterators_and_Generators +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Details_of_the_Object_Model", "Web/JavaScript/Guide/Meta_programming")}}
+ +

Processare ognuno degli elementi in una collezione è un'operazione molto comune. JavaScript fornisce tutta una serie di costrutti per iterare una collezione di elementi, dai semplici cicli {{jsxref("Statements/for","for")}} a {{jsxref("Global_Objects/Array/map","map()")}} e {{jsxref("Global_Objects/Array/filter","filter()")}}. Iterators e Generators portano il concetto di iterazione direttamente al cuore del linguaggio e forniscono un meccanismo per personalizzare i cicli {{jsxref("Statements/for...of","for...of")}}.

+ +

Per maggiori dettagli, vedi anche:

+ + + +

Iterators

+ +

Un oggetto è un iterator quando sa come accedere agli elementi di una collezione uno per volta, conservando l'informazione sulla sua posizione corrente nella sequenza. In Javascript un iterator è un oggetto che implementa il metodo next() , il quale ritorna l'elemento successivo della sequenza. Questo metodo ritorna un oggetto con due proprietà: done evalue.

+ +

Una volta che è stato creato, un iterator può essere utlizzato esplicitamente chiamando più volte il metodo next().

+ +
function makeIterator(array) {
+    var nextIndex = 0;
+
+    return {
+       next: function() {
+           return nextIndex < array.length ?
+               {value: array[nextIndex++], done: false} :
+               {done: true};
+       }
+    };
+}
+ +

Una volta che un iterator è stato inizializzato, il metodonext() può essere chiamato per accedere a coppie chiave-valore dall'oggetto ritornato:

+ +
var it = makeIterator(['yo', 'ya']);
+console.log(it.next().value); // 'yo'
+console.log(it.next().value); // 'ya'
+console.log(it.next().done);  // true
+ +

Generators

+ +

Nonostante implementare un iterator possa essere utile, richiede una considerevole attenzione nella programmazione a causa del bisogno esplicito di mantenere lo stato interno dell'iteratore. I {{jsxref("Global_Objects/Generator","Generators","","true")}} forniscono una potente alternativa: ti permettono di definire un algoritmo iterativo scrivendo una singola funzione in grado di mantenere il proprio stato.

+ +

Una GeneratorFunction è uno speciale tipo di funzione che opera come una "fabbrica" di iterators. Quando viene eseguita ritorna un nuovo oggetto Generator. Una funzione diventa una GeneratorFunction se usa la sintassi {{jsxref("Statements/function*","function*")}}.

+ +
function* idMaker() {
+  var index = 0;
+  while(true)
+    yield index++;
+}
+
+var gen = idMaker();
+
+console.log(gen.next().value); // 0
+console.log(gen.next().value); // 1
+console.log(gen.next().value); // 2
+// ...
+ +

Iterables

+ +

Un oggetto è un iterable se definisce un comportamento di iterazione, come per esempio quali valori sono considerati in un costrutto {{jsxref("Statements/for...of", "for...of")}}. Alcuni tipi built-in di Javascript (come {{jsxref("Array")}} o {{jsxref("Map")}}) hanno un comportamento predefinito, mentre altri tipi (come {{jsxref("Object")}}) non ce l'hanno.

+ +

Affinché un oggetto possa essere considerato un iterable deve implementare il metodo @@iterator, cioè l'oggetto (o uno degli oggetti che lo precedono nella catena dei prototipi) deve avere una proprietà con una chiave {{jsxref("Symbol.iterator")}}.

+ +

Iterables definiti dall'utente

+ +

Possiamo creare i nostri iterables in questo modo:

+ +
var myIterable = {};
+myIterable[Symbol.iterator] = function* () {
+    yield 1;
+    yield 2;
+    yield 3;
+};
+
+for (let value of myIterable) {
+    console.log(value);
+}
+// 1
+// 2
+// 3
+
+or
+
+[...myIterable]; // [1, 2, 3]
+
+ +

Iterables Built-in

+ +

{{jsxref("String")}}, {{jsxref("Array")}}, {{jsxref("TypedArray")}}, {{jsxref("Map")}} e {{jsxref("Set")}} sono tutti iterables built-in nel linguaggio, perché i loro oggetti prototipi hanno tutti un metodo {{jsxref("Symbol.iterator")}}.

+ +

Sintassi che si aspettano degli iterables

+ +

Alcuni costrutti ed espressioni si aspettano degli iterables, per esempio il ciclo {{jsxref("Statements/for...of","for-of")}}, la {{jsxref("Operators/Spread_operator","sintassi spread","","true")}}, {{jsxref("Operators/yield*","yield*")}}, e l'{{jsxref("Operators/Destructuring_assignment","assegnamento di destrutturazione","","true")}}.

+ +
for (let value of ['a', 'b', 'c']) {
+    console.log(value);
+}
+// "a"
+// "b"
+// "c"
+
+[...'abc']; // ["a", "b", "c"]
+
+function* gen() {
+  yield* ['a', 'b', 'c'];
+}
+
+gen().next(); // { value: "a", done: false }
+
+[a, b, c] = new Set(['a', 'b', 'c']);
+a; // "a"
+
+
+ +

Generators avanzati

+ +

I generators calcolano i loro valori solo quando vengono effettivamente richiesti, il che gli permette di rappresentare sequenze che sono troppo onerose da calcolare, o perfino sequenze infinite, come nella funzione idMaker().

+ +

Il metodo {{jsxref("Global_Objects/Generator/next","next()")}} accetta anche un valore che può essere utilizzato per modificare lo stato interno di un generatore. Un valore passato a next() sarà trattato come il risultato dell'ultima espressione yield che ha messo in pausa il generator.

+ +

Ecco un generator che produce una sequenza di numeri di Fibonacci. In questo generator il metodonext(x) può essere utilizzato per reinizializzare la sequenza:

+ +
function* fibonacci() {
+  var fn1 = 0;
+  var fn2 = 1;
+  while (true) {
+    var current = fn1;
+    fn1 = fn2;
+    fn2 = current + fn1;
+    var reset = yield current;
+    if (reset) {
+        fn1 = 0;
+        fn2 = 1;
+    }
+  }
+}
+
+var sequence = fibonacci();
+console.log(sequence.next().value);     // 0
+console.log(sequence.next().value);     // 1
+console.log(sequence.next().value);     // 1
+console.log(sequence.next().value);     // 2
+console.log(sequence.next().value);     // 3
+console.log(sequence.next().value);     // 5
+console.log(sequence.next().value);     // 8
+console.log(sequence.next(true).value); // 0
+console.log(sequence.next().value);     // 1
+console.log(sequence.next().value);     // 1
+console.log(sequence.next().value);     // 2
+ +

Puoi forzare un generator a lanciare una eccezione chiamando il suo metodo {{jsxref("Global_Objects/Generator/throw","throw()")}} e passandogli il valore che dovrebbe lanciare. Questa eccezione sarà lanciata dal corrente context sospeso del generator, come se lo yield che è attualmente sospeso fosse invece una dichiarazione throw value.

+ +

Se non si incontra uno yield durante la risoluzione della eccezione lanciata, allora l'eccezione si propagherà fino alla chiamata athrow(), e in tutte le successive chiamate a next() la proprietà done saràtrue.

+ +

I generators hanno un metodo {{jsxref("Global_Objects/Generator/return","return(value)")}} che ritorna un valore e termina il generator stesso.

+ +

{{PreviousNext("Web/JavaScript/Guide/Details_of_the_Object_Model", "Web/JavaScript/Guide/Meta_programming")}}

diff --git a/files/it/web/javascript/guide/loops_and_iteration/index.html b/files/it/web/javascript/guide/loops_and_iteration/index.html new file mode 100644 index 0000000000..c677151181 --- /dev/null +++ b/files/it/web/javascript/guide/loops_and_iteration/index.html @@ -0,0 +1,340 @@ +--- +title: Cicli e iterazioni +slug: Web/JavaScript/Guida/Loops_and_iteration +tags: + - Guide + - JavaScript + - Loop + - Sintassi +translation_of: Web/JavaScript/Guide/Loops_and_iteration +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Control_flow_and_error_handling", "Web/JavaScript/Guide/Functions")}}
+ +

I cicli offrono un modo semplice e rapido per fare cose ripetutamente. Questo capitolo della guida al JavaScript introduce i diversi metodi di iterazione disponibili in JavaScript.

+ +

Si può pensare al loop come ad una versione computerizzata di un gioco dove si dice a qualcuno di andare X passi in una direzione e Y passi in un'atra; per esempio "vai 5 passi a est" può essere espresso in questo modo con un loop:

+ +
var passi;
+for (passi = 0; passi < 5; passi++) {
+  // Viene eseguito 5 volte, con un valore di passi che va da 0 a 4.
+  console.log('Fai un passo verso est');
+}
+
+ +

Ci sono differenti tipi di ciclo, ma sono essenzialmente tutti la stessa cosa: ripetono un'azione o un insieme di azioni un certo numero di volte (è possibile che questo numero sia anche 0).

+ +

I diversi meccanismi di ciclo offrono differenti modi di determinare l'inizio e la fine del ciclo. Ci sono casi che si prestano più ad un tipo di ciclo rispetto ad altri.

+ +

Le istruzioni per i loop foriti in JavaScript sono:

+ + + +

Istruzione for

+ +

Il {{jsxref("statements/for","ciclo for")}} continua finché la condizione valutata non è falsa. Il fir loop JavaScript è simile a quello del Java e de C. L'istruzione for è definita come segue:

+ +
for ([espressioneIniziale]; [condizione]; [incremento])
+  istruzione
+
+ +

Quando viene eseguito un ciclo for, questo è ciò che accade:

+ +
    +
  1. espressioneIniziale, se esiste, viene eseguita. L'espressione di solito inizializza uno o più indici, ma la sintassi permette di scrivere espressioni con diversi gradi di compessità. Questa espressione può anche dichiarare delle variabili.
  2. +
  3. La condizione viene verificata. Se il suo valore è true, l'espressione istruzione viene eseguita. Se invece condizione è false, il ciclo finisce. Se condizione è omessa, l'espressione si assume sia true.
  4. +
  5. istruzione viene esguita. Per eseguire diverse istruzioni, è necessario usare il blocco ({ ... }) per raggrupparle.
  6. +
  7. Viene incrementata la l'espressione incremento, se esiste, eseguita, e il ciclo for va al passo successivo.
  8. +
+ +

Esempio

+ +

Il seguente esempio contiene un ciclo for che conta il numero di opzioni selezionate in una lista a scorrimento (a {{HTMLElement("select")}} che permette selezioni multiple). L'istruzione for dichiara una variabile i e la inizializza a zero. Controlla che i sia minore del numero di opzioni dell'elemento <select> , esegue l'istruzione if e incrementa i di uno alla fine di ogni ciclo.

+ +
<form name="selectForm">
+  <p>
+    <label for="musicTypes">Choose some music types, then click the button below:</label>
+    <select id="musicTypes" name="musicTypes" multiple="multiple">
+      <option selected="selected">R&B</option>
+      <option>Jazz</option>
+      <option>Blues</option>
+      <option>New Age</option>
+      <option>Classical</option>
+      <option>Opera</option>
+    </select>
+  </p>
+  <p><input id="btn" type="button" value="Quanti sono selezionati?" /></p>
+</form>
+
+<script>
+function howMany(selectObject) {
+  var numberSelected = 0;
+  for (var i = 0; i < selectObject.options.length; i++) {
+    if (selectObject.options[i].selected) {
+      numberSelected++;
+    }
+  }
+  return numberSelected;
+}
+
+var btn = document.getElementById("btn");
+btn.addEventListener("click", function(){
+  alert('Number of options selected: ' + howMany(document.selectForm.musicTypes))
+});
+</script>
+
+
+ +

Istruzione do...while

+ +

Il ciclo {{jsxref("statements/do...while", "do...while")}} si ripete finché la condizione non è falsa. Il do...while è viene definito come segue:

+ +
do
+  istruzione
+while (condizione);
+
+ +

l'istruzione viene eseguita una volta prima che la condizione venga controllata. Per eseguire più istruzioni, è necessario usare il blocco ({ ... }) . Se la condizione è vera l'istruzione viene eseguita nuovamente. Alla fine di ogni esecuzione di istruzione, condizione viene controllata. Quando condizione è falsa l'esecuzione del ciclo do..while termina.

+ +

Esempio

+ +

Nel seguente esempio il ciclo do..while itera almeno una volta e continua finché il valore di i è minore di 5.

+ +
var i = 0;
+do {
+  i += 1;
+  console.log(i);
+} while (i < 5);
+ +

Istruzione while

+ +

Il ciclo {{jsxref("statements/while","while")}} esegue un'istruzione fino a quando una condizione è true. Ecco un esempio si un ciclo while:

+ +
while (condizione)
+  istruzione   //...statement
+
+ +

Se condizione diventa false, istruzione non viene eseguita a si passa ad eseguire i comandi successivi.

+ +

Durante il ciclo condizione viene testata prima di eseguire istruzione. Se condizione è true, istruzione viene esguita e condizione viene verificata nuovamente. Se condizione è false il ciclo di ferma e viene eseguito il codice successivo al ciclo while.

+ +

Per eseguire istruzioni multiple, è necessario usare il blocco ({ ... }) così da raggruppare le istruzioni.

+ +

Esempio 1

+ +

Il seguente esempio di ciclo while si ripete fino a quando n è minore di tre:

+ +
var n = 0;
+var x = 0;
+while (n < 3) {
+  n++;
+  x += n;
+}
+
+ +

Ad ogni iterazione, il ciclo incrementa n e aggiunge quel valore a x. Pertanto,x e n assumono i seguenti valori:

+ + + +

Dopo aver completato il terzo passaggio, la condizione n < 3 non è più vera, quindi il ciclo termina.

+ +

Esempio 2

+ +

Evita loop infiniti. Assicurati che la condizione in un loop alla fine diventi falsa; altrimenti, il ciclo non terminerà mai. Le istruzioni nel seguente ciclo while vengono eseguite per sempre perché la condizione non diventa mai falsa:

+ +
+
//I loop infiniti non vanno affatto bene
+while (true) {
+  console.log("Buongiorno, Mondo");
+}
+
+ +

Istruzione "etichettata"

+ +

Un {{jsxref("statements/label","label")}} fornisce un'istruzione con un identificatore che ti consente di fare riferimento ad esso altrove nel tuo programma. Ad esempio, è possibile utilizzare un'etichetta per identificare un ciclo e quindi utilizzare le istruzioni breakcontinue per indicare se un programma deve interrompere il loop o continuare la sua esecuzione.

+ +

La sintassi dell'istruzione etichettata è simile alla seguente:

+ +
label :
+   istruzione // statement
+
+ +

Il valore dell'etichetta label può essere qualsiasi identificatore JavaScript che non sia una parola riservata. L'affermazione che ti identifichi con un'etichetta statement può essere una qualsiasi affermazione.

+ +

Esempio

+ +

In questo esempio, la label markLoop identifica un ciclo while.

+ +
markLoop:
+while (theMark == true) {
+   doSomething();
+}
+ +

Istruzione break

+ +

Utilizzare l'istruzione {{jsxref("statements/break","break")}} per terminare un ciclo, uno switch o in congiunzione con un'istruzione etichettata.

+ + + +

La sintassi dell'istruzione break è simile a questa:

+ +
break [label];
+
+ +

La prima forma della sintassi termina il ciclo switch di chiusura più interno; la seconda forma della sintassi termina l'istruzione dell'etichettata specificata.

+ +

Esempio 1

+ +

L'esempio seguente esegue iterazioni attraverso gli elementi di un array (una matrice) fino a quando non trova l'indice di un elemento il cui valore è theValue:

+ +
for (var i = 0; i < a.length; i++) {
+  if (a[i] == theValue) {
+    break;
+  }
+}
+ +

Esempio 2: Breaking to a label - Interruzione su un'etichetta

+ +
var x = 0;
+var z = 0;
+labelCancelLoops: while (true) {
+  console.log("Outer loops: " + x);
+  x += 1;
+  z = 1;
+  while (true) {
+    console.log("Inner loops: " + z);
+    z += 1;
+    if (z === 10 && x === 10) {
+      break labelCancelLoops;
+    } else if (z === 10) {
+      break;
+    }
+  }
+}
+ +

Istruzione continue

+ +

The {{jsxref("statements/continue","continue")}} statement can be used to restart a while, do-while, for, or label statement.

+ + + +

La sintassi dell'istruzione continue ha il seguente aspetto:

+ +
continue [label];
+
+ +

Esempio 1

+ +

L'esempio seguente mostra un ciclo while con un'istruzione continue che viene eseguita quando il valore di i è tre. Quindi, n assume i valori uno, tre, sette e dodici.

+ +
var i = 0;
+var n = 0;
+while (i < 5) {
+  i++;
+  if (i == 3) {
+    continue;
+  }
+  n += i;
+}
+ +

Esempio 2

+ +

Una dichiarazione etichettata checkiandj contiene una dichiarazione etichettata checkj. Se si incontra continue il programma termina l'iterazione corrente di checkj e inizia la successiva iterazione. Ogni volta che si incontra continue, checkj viene reiterato finché la condizione non restituisce false. Quando viene restituito false, il resto dell'istruzione checkiandj è completato e checkiandj reiterate fino a quando la condizione non restituisce false. Quando viene restituito false, il programma continua con la seguente istruzione checkiandj.

+ +

Se continue ha un'etichetta di checkiandj, il programma continuerà nella parte superiore del checkiandj istruzione.

+ +
var i = 0;
+var j = 10;
+checkiandj:
+  while (i < 4) {
+    console.log(i);
+    i += 1;
+    checkj:
+      while (j > 4) {
+        console.log(j);
+        j -= 1;
+        if ((j % 2) == 0) {
+          continue checkj;
+        }
+        console.log(j + ' is odd.');
+      }
+      console.log('i = ' + i);
+      console.log('j = ' + j);
+}
+ +

Istruzione for...in

+ +

L'istruzione {{jsxref("statements/for...in","for...in")}} itera una variabile specificata su tutte le proprietà enumerabili di un oggetto. Per ogni proprietà distinta, JavaScript esegue le istruzioni specificate. L'istruzione for...in ha il seguente aspetto:

+ +
for (variabile in oggetto) {
+  istruzione
+}
+// for (variable in object) {
+//  statements
+// }
+
+ +

Esempio

+ +

La seguente funzione prende come argomento un oggetto e il nome dell'oggetto. Quindi itera su tutte le proprietà dell'oggetto e restituisce una stringa che elenca i nomi delle proprietà e i loro valori.

+ +
function dump_props(obj, obj_name) {
+  var result = "";
+  for (var i in obj) {
+    result += obj_name + "." + i + " = " + obj[i] + "<br>";
+  }
+  result += "<hr>";
+  return result;
+}
+
+ +

Per un oggetto car con proprietà make e model, result sarebbe:

+ +
car.make = Ford
+car.model = Mustang
+
+ +

Arrays / Matrici

+ +

Anche se può essere allettante usarla come un modo per iterare sugli elementi {{jsxref("Array")}} , l'istruzione the for...in restituirà il nome delle proprietà definite dall'utente oltre agli indici numerici. Quindi è meglio usare un ciclo tradizionale {{jsxref("statements/for","for")}} con un indice numerico quando si itera su array, perché l'istruzione for...in itera sulle proprietà definite dall'utente oltre agli elementi dell'array, se si modifica l'oggetto Array, (come ad esempio l'aggiunta di proprietà o metodi personalizzati).

+ +

Istruzione for...of

+ +

L'istruzione {{jsxref("statements/for...of","for...of")}} crea un ciclo che itera su oggetti iterabili (inclusi oggetti di tipo {{jsxref("Array")}}, {{jsxref("Map")}}, {{jsxref("Set")}}, {{jsxref("functions/arguments","arguments")}} e così via), richiamando un aggancio di iterazione personalizzato con istruzioni da eseguire per il valore di ogni proprietà distinta.

+ +
for (variabile di oggetto) {
+  istruzione
+}
+ +

Il seguente esempio mostra la differenza tra un ciclo for...of e un {{jsxref("statements/for...in","for...in")}} ciclo continuo. Mentre for...in itera sopra i nomi delle proprietà, for...of itera sui valori delle proprietà:

+ +
let arr = [3, 5, 7];
+arr.foo = "hello";
+
+for (let i in arr) {
+   console.log(i); // logs "0", "1", "2", "foo"
+}
+
+for (let i of arr) {
+   console.log(i); // logs "3", "5", "7"
+}
+ +

{{PreviousNext("Web/JavaScript/Guide/Control_flow_and_error_handling", "Web/JavaScript/Guide/Functions")}}

diff --git a/files/it/web/javascript/guide/regular_expressions/index.html b/files/it/web/javascript/guide/regular_expressions/index.html new file mode 100644 index 0000000000..f876045948 --- /dev/null +++ b/files/it/web/javascript/guide/regular_expressions/index.html @@ -0,0 +1,647 @@ +--- +title: Espressioni regolari +slug: Web/JavaScript/Guida/Espressioni_Regolari +translation_of: Web/JavaScript/Guide/Regular_Expressions +--- +
{{jsSidebar("Guida JavaScript")}} {{PreviousNext("Web/JavaScript/Guide/Text_formatting", "Web/JavaScript/Guide/Indexed_collections")}}
+ +

Le espressioni regolari sono schemi usati per confrontare combinazioni di caratteri nelle stringhe. In JavaScript, le espressioni regolari sono anche oggetti. Questi pattern sono usati con i metodi {{jsxref("RegExp.exec", "exec()")}} e {{jsxref("RegExp.test", "test()")}} della classe {{jsxref("RegExp")}}, e con i metodi {{jsxref("String.match", "match()")}},   {{jsxref("String.matchAll", "matchAll()")}}, {{jsxref("String.replace", "replace()")}}, {{jsxref("String.search", "search()")}}, e {{jsxref("String.split", "split()")}} della classe {{jsxref("String")}}. Questo capitolo descrive le espressioni regolari in JavaScript.

+ +

Creazione di un'espressione regolare

+ +

Puoi creare un'espressione regolare in uno dei seguenti modi:

+ + + +

Scrivere uno schema per espressioni regolari

+ +

Uno schema di espressione regolare è composto da caratteri semplici, come /abc/, o da una combinazione di caratteri semplici e speciali, come /ab*c//Chapter (\d+)\.\d*/. L'ultimo esempio include parentesi che sono usate come un dispositivo di memoria. Il confronto fatto con queste parti dello schema è ricordato per usi futuri, come descritto in  {{ web.link("#Using_parenthesized_substring_matches", "Using parenthesized substring matches") }}.

+ +
+

Nota: Se hai già familiarità con la struttura di un'espressione regolare, potresti anche leggere il cheatsheet per una rapida ricerca di un modello/costrutto specifico

+
+ +

Usare modelli semplici

+ +

I modelli semplici sono costituiti da carattrei per i quali si desidera trovare una corrispondenza diretta. Ad esempio, il modello /abc/ corrisponde solo quando esattamente i caratteri "abc" si presentano insieme e in quell'ordine. Una tale corrispondenza avrebbe successo nelle stringhe "Ciao, conosci il tuo abc?" e "Gli ultimi progetti di aeroplani si sono evoluti da slabcraft". In entrambi i casi la corrispondenza con la sottostringa "abc" avviene. Non c'è corrispondenza nella stringa "Grab crab" perché invece di contenere l'esatta sottostringa "abc" coniente la sottostringa "ab c".

+ +

Usare caratteri speciali

+ +

Quando la ricerca di una corrispondenza richiede qualcosa di più di una corrispondenza diretta, come la ricerca di una o più b o la ricerca di spazi bianchi, il modello include caratteri speciali. Ad esempio, per abbinare una singola "a" seguita da zero o più "b" seguita da "c", dovresti usare il modello /ab*c/: il * dopo "b" significa "0 o più occorrenze dell'elemento precedente". Nella stringa "cbbabbbbcdebc", questo modello corrisponderà alla sottostringa "abbbbc".
+
+ La tabella seguente fornisce un elenco completo e una descrizione dei caratteri speciali che possono essere utilizzati nelle espressioni regolari.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Caratteri speciali nelle espressioni regolari
CarattereSignificato/Utilizzo
\ +

Matches according to the following rules:
+
+ A backslash that precedes a non-special character indicates that the next character is special and is not to be interpreted literally. For example, a 'b' without a preceding '\' generally matches lowercase 'b's wherever they occur. But a '\b' by itself doesn't match any character; it forms the special word boundary character.
+
+ A backslash that precedes a special character indicates that the next character is not special and should be interpreted literally. For example, the pattern /a*/ relies on the special character '*' to match 0 or more a's. By contrast, the pattern /a\*/ removes the specialness of the '*' to enable matches with strings like 'a*'.
+
+ Do not forget to escape \ itself while using the RegExp("pattern") notation because \ is also an escape character in strings.

+
^Matches beginning of input. If the multiline flag is set to true, also matches immediately after a line break character.
+
+ For example, /^A/ does not match the 'A' in "an A", but does match the 'A' in "An E".
+
+ The '^' has a different meaning when it appears as the first character in a character set pattern. See complemented character sets for details and an example.
$ +

Matches end of input. If the multiline flag is set to true, also matches immediately before a line break character.

+ +

For example, /t$/ does not match the 't' in "eater", but does match it in "eat".

+
* +

Matches the preceding expression 0 or more times. Equivalent to {0,}.

+ +

For example, /bo*/ matches 'boooo' in "A ghost booooed" and 'b' in "A bird warbled", but nothing in "A goat grunted".

+
+ +

Matches the preceding expression 1 or more times. Equivalent to {1,}.

+ +

For example, /a+/ matches the 'a' in "candy" and all the a's in "caaaaaaandy", but nothing in "cndy".

+
?Matches the preceding expression 0 or 1 time. Equivalent to {0,1}.
+
+ For example, /e?le?/ matches the 'el' in "angel" and the 'le' in "angle" and also the 'l' in "oslo".
+
+ If used immediately after any of the quantifiers *, +, ?, or {}, makes the quantifier non-greedy (matching the fewest possible characters), as opposed to the default, which is greedy (matching as many characters as possible). For example, applying /\d+/ to "123abc" matches "123". But applying /\d+?/ to that same string matches only the "1".
+
+ Also used in lookahead assertions, as described in the x(?=y) and x(?!y) entries of this table.
+  
. +

(The decimal point) matches any single character except the newline character.

+ +

For example, /.n/ matches 'an' and 'on' in "nay, an apple is on the tree", but not 'nay'.

+
(x) +

Matches 'x' and remembers the match, as the following example shows. The parentheses are called capturing parentheses.
+
+ The '(foo)' and '(bar)' in the pattern /(foo) (bar) \1 \2/ match and remember the first two words in the string "foo bar foo bar". The \1 and \2 in the pattern match the string's last two words. Note that \1, \2, \n are used in the matching part of the regex. In the replacement part of a regex the syntax $1, $2, $n must be used, e.g.: 'bar foo'.replace( /(...) (...)/, '$2 $1' ).

+
(?:x)Matches 'x' but does not remember the match. The parentheses are called non-capturing parentheses, and let you define subexpressions for regular expression operators to work with. Consider the sample expression /(?:foo){1,2}/. If the expression was /foo{1,2}/, the {1,2} characters would apply only to the last 'o' in 'foo'. With the non-capturing parentheses, the {1,2} applies to the entire word 'foo'.
x(?=y) +

Matches 'x' only if 'x' is followed by 'y'. This is called a lookahead.

+ +

For example, /Jack(?=Sprat)/ matches 'Jack' only if it is followed by 'Sprat'. /Jack(?=Sprat|Frost)/ matches 'Jack' only if it is followed by 'Sprat' or 'Frost'. However, neither 'Sprat' nor 'Frost' is part of the match results.

+
x(?!y) +

Matches 'x' only if 'x' is not followed by 'y'. This is called a negated lookahead.

+ +

For example, /\d+(?!\.)/ matches a number only if it is not followed by a decimal point. The regular expression /\d+(?!\.)/.exec("3.141") matches '141' but not '3.141'.

+
x|y +

Matches either 'x' or 'y'.

+ +

For example, /green|red/ matches 'green' in "green apple" and 'red' in "red apple."

+
{n}Matches exactly n occurrences of the preceding expression. N must be a positive integer.
+
+ For example, /a{2}/ doesn't match the 'a' in "candy," but it does match all of the a's in "caandy," and the first two a's in "caaandy."
{n,m} +

Where n and m are positive integers and n <= m. Matches at least n and at most m occurrences of the preceding expression. When m is omitted, it's treated as ∞.

+ +

For example, /a{1,3}/ matches nothing in "cndy", the 'a' in "candy," the first two a's in "caandy," and the first three a's in "caaaaaaandy". Notice that when matching "caaaaaaandy", the match is "aaa", even though the original string had more a's in it.

+
[xyz]Character set. This pattern type matches any one of the characters in the brackets, including escape sequences. Special characters like the dot(.) and asterisk (*) are not special inside a character set, so they don't need to be escaped. You can specify a range of characters by using a hyphen, as the following examples illustrate.
+
+ The pattern [a-d], which performs the same match as [abcd], matches the 'b' in "brisket" and the 'c' in "city". The patterns /[a-z.]+/ and /[\w.]+/ match the entire string "test.i.ng".
[^xyz] +

A negated or complemented character set. That is, it matches anything that is not enclosed in the brackets. You can specify a range of characters by using a hyphen. Everything that works in the normal character set also works here.

+ +

For example, [^abc] is the same as [^a-c]. They initially match 'r' in "brisket" and 'h' in "chop."

+
[\b]Matches a backspace (U+0008). You need to use square brackets if you want to match a literal backspace character. (Not to be confused with \b.)
\b +

Matches a word boundary. A word boundary matches the position where a word character is not followed or preceeded by another word-character. Note that a matched word boundary is not included in the match. In other words, the length of a matched word boundary is zero. (Not to be confused with [\b].)

+ +

Examples:
+ /\bm/ matches the 'm' in "moon" ;
+ /oo\b/ does not match the 'oo' in "moon", because 'oo' is followed by 'n' which is a word character;
+ /oon\b/ matches the 'oon' in "moon", because 'oon' is the end of the string, thus not followed by a word character;
+ /\w\b\w/ will never match anything, because a word character can never be followed by both a non-word and a word character.

+ +
+

Note: JavaScript's regular expression engine defines a specific set of characters to be "word" characters. Any character not in that set is considered a word break. This set of characters is fairly limited: it consists solely of the Roman alphabet in both upper- and lower-case, decimal digits, and the underscore character. Accented characters, such as "é" or "ü" are, unfortunately, treated as word breaks.

+
+
\B +

Matches a non-word boundary. This matches a position where the previous and next character are of the same type: Either both must be words, or both must be non-words. The beginning and end of a string are considered non-words.

+ +

For example, /\B../ matches 'oo' in "noonday", and /y\B./ matches 'ye' in "possibly yesterday."

+
\cX +

Where X is a character ranging from A to Z. Matches a control character in a string.

+ +

For example, /\cM/ matches control-M (U+000D) in a string.

+
\d +

Matches a digit character. Equivalent to [0-9].

+ +

For example, /\d/ or /[0-9]/ matches '2' in "B2 is the suite number."

+
\D +

Matches any non-digit character. Equivalent to [^0-9].

+ +

For example, /\D/ or /[^0-9]/ matches 'B' in "B2 is the suite number."

+
\fMatches a form feed (U+000C).
\nMatches a line feed (U+000A).
\rMatches a carriage return (U+000D).
\s +

Matches a single white space character, including space, tab, form feed, line feed. Equivalent to [ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff].

+ +

For example, /\s\w*/ matches ' bar' in "foo bar."

+
\S +

Matches a single character other than white space. Equivalent to [^ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff].

+ +

For example, /\S\w*/ matches 'foo' in "foo bar."

+
\tMatches a tab (U+0009).
\vMatches a vertical tab (U+000B).
\w +

Matches any alphanumeric character including the underscore. Equivalent to [A-Za-z0-9_].

+ +

For example, /\w/ matches 'a' in "apple," '5' in "$5.28," and '3' in "3D."

+
\W +

Matches any non-word character. Equivalent to [^A-Za-z0-9_].

+ +

For example, /\W/ or /[^A-Za-z0-9_]/ matches '%' in "50%."

+
\n +

Where n is a positive integer, a back reference to the last substring matching the n parenthetical in the regular expression (counting left parentheses).

+ +

For example, /apple(,)\sorange\1/ matches 'apple, orange,' in "apple, orange, cherry, peach."

+
\0Matches a NULL (U+0000) character. Do not follow this with another digit, because \0<digits> is an octal escape sequence.
\xhhMatches the character with the code hh (two hexadecimal digits)
\uhhhhMatches the character with the code hhhh (four hexadecimal digits).
\u{hhhh}(only when u flag is set) Matches the character with the Unicode value hhhh (hexadecimal digits).
+ +

Escaping user input to be treated as a literal string within a regular expression can be accomplished by simple replacement:

+ +
function escapeRegExp(string){
+  return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
+}
+ +

Using parentheses

+ +

Parentheses around any part of the regular expression pattern cause that part of the matched substring to be remembered. Once remembered, the substring can be recalled for other use, as described in {{ web.link("#Using_parenthesized_substring_matches", "Using Parenthesized Substring Matches") }}.

+ +

For example, the pattern /Chapter (\d+)\.\d*/ illustrates additional escaped and special characters and indicates that part of the pattern should be remembered. It matches precisely the characters 'Chapter ' followed by one or more numeric characters (\d means any numeric character and + means 1 or more times), followed by a decimal point (which in itself is a special character; preceding the decimal point with \ means the pattern must look for the literal character '.'), followed by any numeric character 0 or more times (\d means numeric character, * means 0 or more times). In addition, parentheses are used to remember the first matched numeric characters.

+ +

This pattern is found in "Open Chapter 4.3, paragraph 6" and '4' is remembered. The pattern is not found in "Chapter 3 and 4", because that string does not have a period after the '3'.

+ +

To match a substring without causing the matched part to be remembered, within the parentheses preface the pattern with ?:. For example, (?:\d+) matches one or more numeric characters but does not remember the matched characters.

+ +

Lavorare con le espressioni regolari

+ +

Le espressioni regolari sono usate con i metodi test and exec di RegExp e con i metodi match, replace, search, and split di String .Questi metodi sono spiegati in dettaglio nelle  JavaScript reference.

+ +

Metodi che usano le espressioni regolari

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MetodoDescrizione
{{jsxref("RegExp.exec", "exec")}} +

Un metodo di RegExp che esegue una ricerca per una corrispondenza in una stringa. Ritorna un array di informazioni, o null se non trova corrispondenze.

+
{{jsxref("RegExp.test", "test")}}Un metodo di RegExp che testa le corrispondenze in una stinga. Ritorna true o false. 
{{jsxref("String.match", "match")}}Un metodo di String che esegue una ricerca per una corrispondenza in una stringa. Ritorna un array di informazioni, o null se non trova corrispondenze.
{{jsxref("String.search", "search")}}A String method that tests for a match in a string. It returns the index of the match, or -1 if the search fails.
{{jsxref("String.replace", "replace")}}A String method that executes a search for a match in a string, and replaces the matched substring with a replacement substring.
{{jsxref("String.split", "split")}}A String method that uses a regular expression or a fixed string to break a string into an array of substrings.
+ +

When you want to know whether a pattern is found in a string, use the test or search method; for more information (but slower execution) use the exec or match methods. If you use exec or match and if the match succeeds, these methods return an array and update properties of the associated regular expression object and also of the predefined regular expression object, RegExp. If the match fails, the exec method returns null (which coerces to false).

+ +

In the following example, the script uses the exec method to find a match in a string.

+ +
var myRe = /d(b+)d/g;
+var myArray = myRe.exec("cdbbdbsbz");
+
+ +

If you do not need to access the properties of the regular expression, an alternative way of creating myArray is with this script:

+ +
var myArray = /d(b+)d/g.exec("cdbbdbsbz"); // equivalent to "cdbbdbsbz".match(/d(b+)d/g);
+
+ +

If you want to construct the regular expression from a string, yet another alternative is this script:

+ +
var myRe = new RegExp("d(b+)d", "g");
+var myArray = myRe.exec("cdbbdbsbz");
+
+ +

With these scripts, the match succeeds and returns the array and updates the properties shown in the following table.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Results of regular expression execution.
ObjectProperty or indexDescriptionIn this example
myArrayThe matched string and all remembered substrings.["dbbd", "bb"]
indexThe 0-based index of the match in the input string.1
inputThe original string."cdbbdbsbz"
[0]The last matched characters."dbbd"
myRelastIndexThe index at which to start the next match. (This property is set only if the regular expression uses the g option, described in {{ web.link("#Advanced_searching_with_flags", "Advanced Searching With Flags") }}.)5
sourceThe text of the pattern. Updated at the time that the regular expression is created, not executed."d(b+)d"
+ +

As shown in the second form of this example, you can use a regular expression created with an object initializer without assigning it to a variable. If you do, however, every occurrence is a new regular expression. For this reason, if you use this form without assigning it to a variable, you cannot subsequently access the properties of that regular expression. For example, assume you have this script:

+ +
var myRe = /d(b+)d/g;
+var myArray = myRe.exec("cdbbdbsbz");
+console.log("The value of lastIndex is " + myRe.lastIndex);
+
+// "The value of lastIndex is 5"
+
+ +

However, if you have this script:

+ +
var myArray = /d(b+)d/g.exec("cdbbdbsbz");
+console.log("The value of lastIndex is " + /d(b+)d/g.lastIndex);
+
+// "The value of lastIndex is 0"
+
+ +

The occurrences of /d(b+)d/g in the two statements are different regular expression objects and hence have different values for their lastIndex property. If you need to access the properties of a regular expression created with an object initializer, you should first assign it to a variable.

+ +

Using parenthesized substring matches

+ +

Including parentheses in a regular expression pattern causes the corresponding submatch to be remembered. For example, /a(b)c/ matches the characters 'abc' and remembers 'b'. To recall these parenthesized substring matches, use the Array elements [1], ..., [n].

+ +

The number of possible parenthesized substrings is unlimited. The returned array holds all that were found. The following examples illustrate how to use parenthesized substring matches.

+ +

The following script uses the {{jsxref("String.replace", "replace()")}} method to switch the words in the string. For the replacement text, the script uses the $1 and $2 in the replacement to denote the first and second parenthesized substring matches.

+ +
var re = /(\w+)\s(\w+)/;
+var str = "John Smith";
+var newstr = str.replace(re, "$2, $1");
+console.log(newstr);
+
+ +

This prints "Smith, John".

+ +

Advanced searching with flags

+ +

Regular expressions have four optional flags that allow for global and case insensitive searching. These flags can be used separately or together in any order, and are included as part of the regular expression.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Regular expression flags
FlagDescription
gGlobal search.
iCase-insensitive search.
mMulti-line search.
yPerform a "sticky" search that matches starting at the current position in the target string. See {{jsxref("RegExp.sticky", "sticky")}}
+ +

To include a flag with the regular expression, use this syntax:

+ +
var re = /pattern/flags;
+
+ +

or

+ +
var re = new RegExp("pattern", "flags");
+
+ +

Note that the flags are an integral part of a regular expression. They cannot be added or removed later.

+ +

For example, re = /\w+\s/g creates a regular expression that looks for one or more characters followed by a space, and it looks for this combination throughout the string.

+ +
var re = /\w+\s/g;
+var str = "fee fi fo fum";
+var myArray = str.match(re);
+console.log(myArray);
+
+ +

This displays ["fee ", "fi ", "fo "]. In this example, you could replace the line:

+ +
var re = /\w+\s/g;
+
+ +

with:

+ +
var re = new RegExp("\\w+\\s", "g");
+
+ +

and get the same result.

+ +

The m flag is used to specify that a multiline input string should be treated as multiple lines. If the m flag is used, ^ and $ match at the start or end of any line within the input string instead of the start or end of the entire string.

+ +

Examples

+ +

The following examples show some uses of regular expressions.

+ +

Changing the order in an input string

+ +

The following example illustrates the formation of regular expressions and the use of string.split() and string.replace(). It cleans a roughly formatted input string containing names (first name first) separated by blanks, tabs and exactly one semicolon. Finally, it reverses the name order (last name first) and sorts the list.

+ +
// The name string contains multiple spaces and tabs,
+// and may have multiple spaces between first and last names.
+var names = "Harry Trump ;Fred Barney; Helen Rigby ; Bill Abel ; Chris Hand ";
+
+var output = ["---------- Original String\n", names + "\n"];
+
+// Prepare two regular expression patterns and array storage.
+// Split the string into array elements.
+
+// pattern: possible white space then semicolon then possible white space
+var pattern = /\s*;\s*/;
+
+// Break the string into pieces separated by the pattern above and
+// store the pieces in an array called nameList
+var nameList = names.split(pattern);
+
+// new pattern: one or more characters then spaces then characters.
+// Use parentheses to "memorize" portions of the pattern.
+// The memorized portions are referred to later.
+pattern = /(\w+)\s+(\w+)/;
+
+// New array for holding names being processed.
+var bySurnameList = [];
+
+// Display the name array and populate the new array
+// with comma-separated names, last first.
+//
+// The replace method removes anything matching the pattern
+// and replaces it with the memorized string—second memorized portion
+// followed by comma space followed by first memorized portion.
+//
+// The variables $1 and $2 refer to the portions
+// memorized while matching the pattern.
+
+output.push("---------- After Split by Regular Expression");
+
+var i, len;
+for (i = 0, len = nameList.length; i < len; i++){
+  output.push(nameList[i]);
+  bySurnameList[i] = nameList[i].replace(pattern, "$2, $1");
+}
+
+// Display the new array.
+output.push("---------- Names Reversed");
+for (i = 0, len = bySurnameList.length; i < len; i++){
+  output.push(bySurnameList[i]);
+}
+
+// Sort by last name, then display the sorted array.
+bySurnameList.sort();
+output.push("---------- Sorted");
+for (i = 0, len = bySurnameList.length; i < len; i++){
+  output.push(bySurnameList[i]);
+}
+
+output.push("---------- End");
+
+console.log(output.join("\n"));
+
+ +

Using special characters to verify input

+ +

In the following example, the user is expected to enter a phone number. When the user presses the "Check" button, the script checks the validity of the number. If the number is valid (matches the character sequence specified by the regular expression), the script shows a message thanking the user and confirming the number. If the number is invalid, the script informs the user that the phone number is not valid.

+ +

Within non-capturing parentheses (?: , the regular expression looks for three numeric characters \d{3} OR | a left parenthesis \( followed by three digits \d{3}, followed by a close parenthesis \), (end non-capturing parenthesis )), followed by one dash, forward slash, or decimal point and when found, remember the character ([-\/\.]), followed by three digits \d{3}, followed by the remembered match of a dash, forward slash, or decimal point \1, followed by four digits \d{4}.

+ +

The Change event activated when the user presses Enter sets the value of RegExp.input.

+ +
<!DOCTYPE html>
+<html>
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+    <meta http-equiv="Content-Script-Type" content="text/javascript">
+    <script type="text/javascript">
+      var re = /(?:\d{3}|\(\d{3}\))([-\/\.])\d{3}\1\d{4}/;
+      function testInfo(phoneInput){
+        var OK = re.exec(phoneInput.value);
+        if (!OK)
+          window.alert(phoneInput.value + " isn't a phone number with area code!");
+        else
+          window.alert("Thanks, your phone number is " + OK[0]);
+      }
+    </script>
+  </head>
+  <body>
+    <p>Enter your phone number (with area code) and then click "Check".
+        <br>The expected format is like ###-###-####.</p>
+    <form action="#">
+      <input id="phone"><button onclick="testInfo(document.getElementById('phone'));">Check</button>
+    </form>
+  </body>
+</html>
+
+ +
{{PreviousNext("Web/JavaScript/Guide/Text_formatting", "Web/JavaScript/Guide/Indexed_collections")}}
-- cgit v1.2.3-54-g00ecf