diff options
Diffstat (limited to 'files/it/web/javascript/a_re-introduction_to_javascript/index.html')
-rw-r--r-- | files/it/web/javascript/a_re-introduction_to_javascript/index.html | 967 |
1 files changed, 967 insertions, 0 deletions
diff --git a/files/it/web/javascript/a_re-introduction_to_javascript/index.html b/files/it/web/javascript/a_re-introduction_to_javascript/index.html new file mode 100644 index 0000000000..e0d779e1b1 --- /dev/null +++ b/files/it/web/javascript/a_re-introduction_to_javascript/index.html @@ -0,0 +1,967 @@ +--- +title: Una reintroduzione al Java Script (Tutorial JS) +slug: Web/JavaScript/A_re-introduction_to_JavaScript +translation_of: Web/JavaScript/A_re-introduction_to_JavaScript +original_slug: Web/JavaScript/Una_reintroduzione_al_JavaScript +--- +<h2 id="Introduzione">Introduzione</h2> + +<p>Perchè una reintroduzione? Perchè <a href="/en-US/docs/JavaScript" title="JavaScript">JavaScript</a> ha la ragionevole pretesa di essere <a class="external" href="http://javascript.crockford.com/javascript.html">il linguaggio di programmazione più frainteso del mondo</a>. Benchè spesso considerato ironicamente come un giocattolo, la sua ingannevole semplicità nasconde alcune potenti caratteristiche. JavaScript viene attualmente utilizzato da un numero incredibile di applicazioni di alto profilo, che mostrano come la conoscenza profonda di questa tecnologia sia un importante abilità per qualunque sviluppatore web.</p> + +<p>È utile iniziare con un accenno alla storia del linguaggio. JavaScript fu creato nel 1995 da Brendan Eich, mentre lavorava come ingegnere presso Netscape, e rilasciata per la prima volta con Netscape 2 all'inizio del 1996. Originariamente doveva essere chiamato LiveScript, ma fu poi rinominato in Javacript per una fatalmente dannosa decisione di marketing che tentava di approfittare della popolarità del linguaggio Java della Sun Microsystem — nonostante abbiano molto poco in comune. <span class="short_text" id="result_box" lang="it"><span class="hps">Questa è stata una</span> <span class="hps">fonte di confusione</span> <span class="hps">da allora.</span></span></p> + +<p>Diversi mesi dopo, Microsoft rilasciò JScript con Internet Explorer 3, un linguaggio che lavorava in modo simile a JavaScript ed era quasi del tutto compatibile con esso. Netscape sottomise il linguaggio alla <a class="external" href="http://www.ecma-international.org/">Ecma International</a>, un'organizzazione europea di standardizzazione, che porta alla nascita della prima edizione degli standard <a href="/en-US/docs/JavaScript/Language_Resources" title="ECMAScript">ECMAScript</a>. Lo standard ricevette un significativo aggiornamento come <a class="external" href="http://www.ecma-international.org/publications/standards/Ecma-262.htm">ECMAScript edition 3</a> nel 1999, ed è rimasto più o meno stabile da allora. La quarta edizione fu abbandonata a causa delle differenze di vedute sulla complessità del linguaggio. Molte parti della quarta edizione formano la base del nuovo ECMAScript edizione 5, pubblicato nel dicembre del 2009, e per la sesta edizione pubblicata a giugno 2015.</p> + +<p>Diversamente dalla maggior parte dei linguaggi di programmazione, il linguaggio JavaScript non ha il concetto di input e output. È stato concepito per essere eseguito come linguaggio di scripting in un ambiente ospite, ed è responsabilità dell'ambiente ospite fornire meccanismi per comunicare con il mondo esterno. L'ambiente ospite più comune è il browser, ma interpreti JavaScript possono essere trovati anche in Adobe Acrobat, Photoshop, motore Widget di Yahoo! , e addirittura in ambienti lato server o in desktop environment come GNOME (una delle GUI più popolari per i sistemi GNU/Linux) e altri ancora.</p> + +<h2 id="Panoramica">Panoramica</h2> + +<p>JavaScript è un linguaggio dinamico orientato agli oggetti; esso ha tipi e operatori, oggetti nucleo, e metodi. La sua sintassi deriva dai linguaggi Java e C, quindi molte strutture utilizzate da questi linguaggi ricorrono anche in JavaScript. Una delle differenze chiave è che JavaScript non ha classi; invece, la funzionalità di classe è realizzata dai prototipi oggetto. L'altra differenza principale è che le funzioni sono oggetti, dando alle funzioni la capacità di mantenere codice eseguibile ed essere passate in giro come ogni altro oggetto.</p> + +<p><span id="result_box" lang="it"><span class="hps">Cominciamo</span> <span class="hps">guardando il</span> <span class="hps">blocco di costruzione</span> <span class="hps">di qualsiasi linguaggio</span></span>: i tipi. I programmmi JavaScript manipolano valori, e tutti quei valori appartengono ad un tipo. I tipi JavaScript sono:</p> + +<ul> + <li><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Number" title="JavaScript/Reference/Global_Objects/Number">Numeri</a></li> + <li><a href="/en-US/docs/JavaScript/Reference/Global_Objects/String" title="JavaScript/Reference/Global_Objects/String">Stringhe</a></li> + <li><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Boolean" title="JavaScript/Reference/Global_Objects/Boolean">Booleani</a></li> + <li><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Function" title="JavaScript/Reference/Global_Objects/Function">Funzioni</a></li> + <li><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Object" title="JavaScript/Reference/Global_Objects/Object">Oggetti</a></li> +</ul> + +<p>... oh, e Undefined (indefiniti) e Null (nulli), che sono leggermente strani. E gli <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Array" title="JavaScript/Reference/Global_Objects/Array">Array</a>, che sono un tipo speciale di oggetto. E <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Date" title="JavaScript/Reference/Global_Objects/Date">Date</a> ed <a href="/en-US/docs/JavaScript/Reference/Global_Objects/RegExp" title="JavaScript/Reference/Global_Objects/RegExp">Espressioni regolari</a>, che sono oggetti che si ottengono gratuitamente. E per essere tecnicamente precisi, le funzioni sono solo un tipo speciale di oggetto. Quindi il diagramma dei tipi somiglia più a questo:</p> + +<ul> + <li>Numeri</li> + <li>Stringhe</li> + <li>Booleani</li> + <li>Oggetti + <ul> + <li>Funzioni</li> + <li>Array</li> + <li>Date</li> + <li>ExpReg</li> + </ul> + </li> + <li>Null</li> + <li>Undefined</li> +</ul> + +<p>E ci sono anche alcuni tipi nativi di <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Error" title="JavaScript/Reference/Global_Objects/Error">Errori</a>. Comunque, le cose sono molto più semplici se ci atteniamo al primo diagramma</p> + +<h2 id="Numeri">Numeri</h2> + +<p>I numeri in JavaScript sono in formato 64-bit a doppia precisione valore del IEEE 754, secondo le specifiche. Questo ha qualche interessante conseguenza. <span id="result_box" lang="it"><span class="hps">Non esiste una cosa</span> <span class="hps">come</span> <span class="hps">un intero</span> <span class="hps">in JavaScript,</span> <span class="hps">quindi bisogna</span> stare<span class="atn hps"> un pò </span><span>attenti con</span> <span class="hps">la vostra aritmetica</span><span>, se</span> <span class="hps">siete abituati alla</span> <span class="hps">matematica</span> <span class="hps">in C</span> <span class="hps">o Java</span></span>. Stare attenti a cose come:</p> + +<pre class="eval notranslate">0.1 + 0.2 == 0.30000000000000004 +</pre> + +<p>In pratica, i valori interi sono trattati come int a 32-bit (e sono memorizzati in questo modo in alcune implementazioni dei browser), che può essere importante per operazioni in bit. Per dettagli, consulta <a class="external" href="http://www.hunlock.com/blogs/The_Complete_Javascript_Number_Reference" title="http://www.hunlock.com/blogs/The_Complete_Javascript_Number_Reference">La Guida Completa sui Numeri JavaScript</a>.</p> + +<p>Gli <a href="/en-US/docs/JavaScript/Reference/Operators/Arithmetic_Operators" title="JavaScript/Reference/Operators/Arithmetic_Operators">operatori numerici</a> standard sono supportati, incluso addizione, sottrazione, modulo (o resto) aritmetico e così via. Vi sono anche oggetti nativi che non sono stati menzionati prima, chiamati <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Math" title="JavaScript/Reference/Global_Objects/Math">Math</a> per trattare funzioni matematiche più avanzate e costanti:</p> + +<pre class="brush: js notranslate">Math.sin(3.5); +var d = Math.PI * r * r; +</pre> + +<p>E' possibile convertire una stringa in un intero utilizzando la funzione nativa <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/parseInt" title="JavaScript/Reference/Global_Functions/parseInt">parseInt()</a></code>. Questo prende la base per la conversione come secondo argomento opzionale, che si dovrebbe fornire sempre:</p> + +<pre class="brush: js notranslate">> parseInt("123", 10) +123 +> parseInt("010", 10) +10 +</pre> + +<p>Se non si fornisce la base, si possono ricevere risultati inattesi:</p> + +<pre class="brush: js notranslate">> parseInt("010") +8 +</pre> + +<p>Questo succede perchè la funzione <code>parseInt</code> ha deciso di trattare la stringa come un ottale a causa del primo 0.</p> + +<p>Se si vuole convertire un numero binario in un intero, basta cambiare la base:</p> + +<pre class="brush: js notranslate">> parseInt("11", 2) +3 +</pre> + +<p>Similmente, è possibile analizzare numeri in virgola mobile usando la funzione nativa <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/parseFloat" title="JavaScript/Reference/Global Objects/parseFloat">parseFloat()</a></code> che utilizza sempre la base 10 diversamente dalla cugina <a href="/en-US/docs/JavaScript/Reference/Global_Objects/parseInt" title="JavaScript/Reference/Global Objects/parseInt"><code>parseInt()</code></a>.</p> + +<p>E' inoltre possibile utilizzare l'operatore unario <code>+</code> per convertire valori in numeri:</p> + +<pre class="notranslate">> + "42" +42 +</pre> + +<p>Un valore speciale chiamato <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/NaN" title="JavaScript/Reference/Global_Properties/NaN">NaN</a></code> (abbreviazione per "Not a Number" - Non un Numero) viene restituita se la stringa non è numerica:</p> + +<pre class="brush: js notranslate">> parseInt("hello", 10) +NaN +</pre> + +<p>Il <code>NaN</code> è tossico: se viene fornito come input a qualsiasi operazione matematica, il risultato sarà anch'esso <code>NaN</code>:</p> + +<pre class="brush: js notranslate">> NaN + 5 +NaN +</pre> + +<p>E' possibile verificare se <code>NaN</code> usando la funzione nativa <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/isNaN" title="JavaScript/Reference/Global_Functions/isNaN">isNaN()</a></code>:</p> + +<pre class="brush: js notranslate">> isNaN(NaN) +true +</pre> + +<p>Anche JavaScript ha i valori speciali <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Infinity" title="JavaScript/Reference/Global_Properties/Infinity">Infinity</a></code> e <code>-Infinity</code>:</p> + +<pre class="brush: js notranslate">> 1 / 0 +Infinity +> -1 / 0 +-Infinity +</pre> + +<p>E' possibile analizzare i valori <code>Infinity</code>, <code>-Infinity</code> e <code>NaN</code> usando la funzione nativa <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/isFinite" title="JavaScript/Reference/Global_Functions/isFinite">isFinite()</a></code>:</p> + +<pre class="brush: js notranslate">> isFinite(1/0) +false +> isFinite(-Infinity) +false +> isFinite(NaN) +false +</pre> + +<div class="note"><strong>Nota:</strong> Le funzioni <a href="/en-US/docs/JavaScript/Reference/Global_Objects/parseInt" title="JavaScript/Reference/Global Objects/parseInt"><code>parseInt()</code></a> e <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/parseFloat" title="JavaScript/Reference/Global Objects/parseFloat">parseFloat()</a></code> analizzano una stringa finchè raggiungono un carattere che è non è valido per il formato numerico specificato, quindi restituiscono il numero analizzato fino a quel punto. Tuttavia l'operatore "+" converte semplicemente la stringa a <code>NaN</code> se è presente in essa qualche carattere invalido. E' sufficiente provare ad eseguire l'analisi della stringa "10.2abc" con ogni metodo da soli utilizzando la console e sarà possibile capire meglio le differenze.</div> + +<h2 id="Stringhe">Stringhe</h2> + +<p>Le stringhe in JavaScript sono sequenze di caratteri. Più precisamente, sono sequenze di <a href="/en-US/docs/JavaScript/Guide/Obsolete_Pages/Unicode" title="JavaScript/Guide/Unicode">Caratteri Unicode</a>, con ogni carattere rappresentato da un numero a 16-bit. <span id="result_box" lang="it"><span class="alt-edited hps">Questa dovrebbe essere</span> <span class="alt-edited hps">una buona notizia per</span> <span class="hps">tutti coloro che hanno</span> <span class="hps">avuto a che fare</span> <span class="hps">con l'internazionalizzazione</span><span>.</span></span></p> + +<p>Se si vuole rappresentare un singolo carattere, occorre semplicemente utilizzare una stringa di lunghezza 1.</p> + +<p>Per trovare la lunghezza di una stringa, accedere la sua proprietà <code><a href="/en-US/docs/JavaScript/Reference/Global_Objects/String/length" title="JavaScript/Reference/Global_Objects/String/length">length</a></code>:</p> + +<pre class="brush: js notranslate">> "hello".length +5 +</pre> + +<p>Ecco il nostro primo assaggio degli oggetti JavaScript! E' stato menzionato che le stringhe sono anch'esse oggetti? Ed hanno anche <a href="/en-US/docs/JavaScript/Reference/Global_Objects/String#Methods" title="JavaScript/Reference/Global_Objects/String#Methods">metodi</a>:</p> + +<pre class="brush: js notranslate">> "hello".charAt(0) +h +> "hello, world".replace("hello", "goodbye") +goodbye, world +> "hello".toUpperCase() +HELLO +</pre> + +<h2 id="Altri_tipi">Altri tipi</h2> + +<p>JavaScript distingue tra <code>null</code>, che è un oggetto di tipo 'object' che indica un mancanza deliberata di valore, e <code>undefined</code>, che è un oggetto di tipo 'undefined' che indica un valore non inizializzato — ossia un valore che non è stato ancora assegnato. Parleremo delle variabili più avanti, ma in JavaScript è possibile dichiarare una variabile senza assegnarle un valore. Facendo questo, il tipo della variabile creata sarà <code>undefined</code>.</p> + +<p>JavaScript ha il tipo booleano, con possibili valori <code>true</code> (vero) e <code>false</code> (falso) (entrambi i quali sono parole chiave). Qualunque valore può essere convertito in booleano seguendo le seguenti regole:</p> + +<ol> + <li><code>false</code>, <code>0</code>, la stringa vuota (<code>""</code>), <code>NaN</code>, <code>null</code>, e <code>undefined</code> diventano tutti <code>false</code></li> + <li>tutti gli altri valori diventano <code>true</code></li> +</ol> + +<p>E' possibile eseguire questa conversione esplicitamente usando la funzione <code>Boolean()</code>:</p> + +<pre class="brush: js notranslate">> Boolean("") +false +> Boolean(234) +true +</pre> + +<p>Tuttavia, questo raramente è necessario, JavaScript eseguirà silenziosamente la conversione quando si aspetta un booleano, così come in una istruzione <code>if</code> (vedi sotto). Per questa ragione, a volte si parla semplicemente di "valori veri" e "valori falsi" valori significativi che diventano <code>true</code> e <code>false</code>, rispettivamente, quando convertiti in booleani. <span id="result_box" lang="it"><span class="hps">In alternativa</span><span>,</span> <span class="hps">tali valori</span> <span class="hps">possono</span> <span class="hps">essere</span> <span class="hps">chiamati</span> <span class="atn hps">"</span><span>truthy</span><span>"</span> <span class="hps">e</span> <span class="atn hps">"</span><span>falsy</span><span>"</span><span>,</span> <span class="hps">rispettivamente</span><span>.</span></span></p> + +<p>Le operazioni booleane come <code>&&</code> (<em>and</em> logico), <code>||</code> (<em>or </em>logico), e <code>!</code> (<em>not </em>logico) sono supportate; vedi sotto.</p> + +<h2 id="Variabili">Variabili</h2> + +<p>Le nuove varibili sono dichiarate in JavaScript utilizzando la parola chiave <code><a href="/en-US/docs/JavaScript/Reference/Statements/var" title="JavaScript/Reference/Statements/var">var</a></code>:</p> + +<pre class="brush: js notranslate">var a; +var name = "simon"; +</pre> + +<p>Se la variabile viene dichiarata senza assegnarle un valore, il suo tipo sarà <code>undefined</code>. </p> + +<p>Una differenza importante rispetto ad altri linguaggi come Java è che in JavaScript, i blocchi non hanno ambito; solo le funzioni hanno ambito. Quindi se una variabile viene definita utilizzando <code>var</code> in una istruzione composta (ad esempio all'interno di una struttura di controllo <code>if</code>), essa sarà visibile da parte dell'intera funzione.</p> + +<h2 id="Operatori">Operatori</h2> + +<p>Gli operatori numerici in JavaScript sono <code>+</code>, <code>-</code>, <code>*</code>, <code>/</code> e <code>%</code> - che è l'operatore per il resto. I valori sono assegnanti usando <code>=</code>, e vi sono anche le istruzioni di assegnamento composte tipo <code>+=</code> e <code>-=</code>. Questi comprimono la forma <code>x = x <em>operatore</em> y</code>.</p> + +<pre class="brush: js notranslate">x += 5 +x = x + 5 +</pre> + +<p>E' possibile utilizzare <code>++</code> e <code>--</code> per incrementare e decrementare rispettivamente. Questi possono essere usati come operatori prefissi o postfissi.</p> + +<p>L'<a href="/en-US/docs/JavaScript/Reference/Operators/String_Operators" title="JavaScript/Reference/Operators/String_Operators">operatore +</a> compie anche la concatenazione di stringhe:</p> + +<pre class="brush: js notranslate">> "hello" + " world" +hello world +</pre> + +<p>Se si somma una stringa ad un numero (o ad un altro valore) tutto viene convertito dalla prima stringa. Questo esempio potrebbe aiutare a chiarire il tutto:</p> + +<pre class="brush: js notranslate">> "3" + 4 + 5 +345 +> 3 + 4 + "5" +75 +</pre> + +<p>Sommare una stringa vuota ad un altro tipo è un utile maniera per convertirlo.</p> + +<p>I <a href="/en-US/docs/JavaScript/Reference/Operators/Comparison_Operators" title="JavaScript/Reference/Operators/Comparison_Operators">confronti</a> in JavaScript possono essere eseguiti usando <code><</code>, <code>></code>, <code><=</code> e <code>>=</code>. Essi funzionano sia per le stringhe che per i numeri. L'uguaglianza è un pochino meno lineare. L'operatore di doppio uguale esegue la coercizione di tipo se viene eseguita tra tipi differenti, con a volte risultati interessanti:</p> + +<pre class="brush: js notranslate">> "dog" == "dog" +true +> 1 == true +true +</pre> + +<p>Per evitare la coercizione di tipo, si utilizza l'operatore triplo uguale:</p> + +<pre class="brush: js notranslate">> 1 === true +false +> true === true +true +</pre> + +<p>Vi sono anche gli operatori !<code>=</code> e <code>!==</code> .</p> + +<p>JavaScript ha inoltre le <a href="/en-US/docs/JavaScript/Reference/Operators/Bitwise_Operators" title="JavaScript/Reference/Operators/Bitwise_Operators">operazioni bit per bit</a>. Se si desidera utilizzarle, sono lì.</p> + +<h2 id="Strutture_di_controllo">Strutture di controllo</h2> + +<p>JavaScript ha una serie di strutture di controllo simili agli altri linguaggi della famiglia del C. Le istruzioni condizionali sono supportate da <code>if</code> e <code>else </code>(se e altrimenti) che possono essere concatenati insieme se desiderato:</p> + +<pre class="brush: js notranslate">var name = "kittens"; +if (name == "puppies") { + name += "!"; +} else if (name == "kittens") { + name += "!!"; +} else { + name = "!" + name; +} +name == "kittens!!" +</pre> + +<p>JavaScript ha il ciclo <code>while</code> ed il ciclo <code>do-while</code>. Il primo è utile per un ciclo basico; il secondo per i cicli che si vuole essere sicuri che vengano eseguiti almeno una volta:</p> + +<pre class="brush: js notranslate">while (true) { + // an infinite loop! +} + +var input; +do { + input = get_input(); +} while (inputIsNotValid(input)) +</pre> + +<p>Il ciclo <code>for</code> in JavaScript è lo stesso che in C e Java: esso permette di fornire le informazioni di controllo per il ciclo in una linea singola.</p> + +<pre class="brush: js notranslate">for (var i = 0; i < 5; i++) { + // Will execute 5 times +} +</pre> + +<p>Gli operatori <code>&&</code>(<em>and</em> logico) e <code>||</code>(<em>or</em> logico) usano un corto-circuito logico, questo significa che quando vengono eseguiti il secondo operando è dipendente dal primo. Questo è utile per verificare oggetti nulli prima di accedere ai loro attributi:</p> + +<pre class="brush: js notranslate">var name = o && o.getName(); +</pre> + +<p>Oppure per impostare valori di default:</p> + +<pre class="brush: js notranslate">var name = otherName || "default"; +</pre> + +<p>JavaScript ha un operatore ternario per espressioni condizionali:</p> + +<pre class="brush: js notranslate">var allowed = (age > 18) ? "yes" : "no"; +</pre> + +<p><span id="result_box" lang="it"><span class="hps">L'istruzione switch</span> <span class="alt-edited hps">può essere utilizzata per</span> <span class="alt-edited hps">più diramazioni</span> <span class="hps">sulla base di un</span> <span class="hps">numero o una stringa</span></span>:</p> + +<pre class="brush: js notranslate">switch(action) { + case 'draw': + drawit(); + break; + case 'eat': + eatit(); + break; + default: + donothing(); +} +</pre> + +<p>Se non viene inserita l'istruzione <code>break</code>, l'esecuzione "naufragherà" nel prossimo livello. Questo è raramente il risultato voluto — <span id="result_box" lang="it"><span class="hps">in realtà</span> <span class="hps">vale la pena</span> <span class="hps">in particolare</span> inserire un <span class="hps">etichettatura</span> <span class="hps">deliberatamente </span><span class="hps">con</span> <span class="hps">un commento,</span> <span class="hps">se vi</span> <span class="hps">vuole</span> <span class="hps">aiutare</span> <span class="hps">il debug</span></span>:</p> + +<pre class="brush: js notranslate">switch(a) { + case 1: // fallthrough + case 2: + eatit(); + break; + default: + donothing(); +} +</pre> + +<p>La clausula default è opzionale. Si possono avere espressioni sia nello switch sia che nel case se si vuole<span class="translation">;</span> <span id="result_box" lang="it"><span class="hps">i confronti</span> <span class="hps">avvengono tra</span> <span class="hps">i due</span> <span class="hps">con</span> <span class="hps">l'operatore ===</span></span>:</p> + +<pre class="brush: js notranslate">switch(1 + 3) { + case 2 + 2: + yay(); + break; + default: + neverhappens(); +} +</pre> + +<h2 id="Oggetti">Oggetti</h2> + +<p>Gli oggetti JavaScript sono semplicemente collezioni di coppie nome-valore. <span class="short_text" id="result_box" lang="it"><span class="hps">Come tali</span><span>,</span> <span class="hps">essi sono</span> <span class="hps">simili a</span></span>:</p> + +<ul> + <li>Dizionari in Python</li> + <li>Hashes in Perl e Ruby</li> + <li>Hash tables in C e C++</li> + <li>HashMaps in Java</li> + <li>Array associativi in PHP</li> +</ul> + +<p>Il fatto che questa struttura dati è così diffusa è la prova della sua versatilità. Dal momento che tutto (barra i tipi base) in JavaScript è un oggetto, qualunque programma JavaScript implica naturalmente un grande ricorso alla ricerca nelle tabelle hash. E' buona cosa che siano così veloci!</p> + +<p>La parte "name" è una stringa JavaScript, mentre il valore può essere qualunque valore JavaScript — incluso più oggetti. Questo permette di costruire strutture dati di complessità arbitraria.</p> + +<p>Ci sono due modalità di base per creare un oggetto vuoto:</p> + +<pre class="brush: js notranslate">var obj = new Object(); +</pre> + +<p>E:</p> + +<pre class="brush: js notranslate">var obj = {}; +</pre> + +<p>Entrambe sono semanticamente equivalenti; la seconda è chiamata sintassi letterale dell'oggetto, ed è più conveniente. Questa sintassi è anche la base del formato JSON e dovrebbe essere preferita ogni volta.</p> + +<p>Una volta creato si può accedere alle proprietà di un oggetto in una o due modalità:</p> + +<pre class="brush: js notranslate">obj.name = "Simon"; +var name = obj.name; +</pre> + +<p>E...</p> + +<pre class="brush: js notranslate">obj["name"] = "Simon"; +var name = obj["name"]; +</pre> + +<p>Anche queste sono semanticamente equivalenti. Il secondo metodo ha il vantaggio che il nome della proprietà viene fornito come stringa, che significa che può essere calcolato durante l'esecuzione e l'utilizzo di questo metodo evita che siano applicate ottimizzazioni del motore JavaScript e minifier. Può essere inoltre usato per impostare o ottenere proprietà con nomi che sono <a href="/en-US/docs/JavaScript/Reference/Reserved_Words" title="JavaScript/Reference/Reserved_Words">parole riservate</a>:</p> + +<pre class="brush: js notranslate">obj.for = "Simon"; // Syntax error, because 'for' is a reserved word +obj["for"] = "Simon"; // works fine +</pre> + +<p>La sintassi dell'oggetto letterale può essere usata per inizializzare un oggetto nella sua interezza:</p> + +<pre class="brush: js notranslate">var obj = { + name: "Carrot", + "for": "Max", + details: { + color: "orange", + size: 12 + } +} +</pre> + +<p><span class="short_text" id="result_box" lang="it"><span class="alt-edited hps">Attributi</span> <span class="hps">di accesso</span> <span class="hps">possono essere concatenati</span></span>:</p> + +<pre class="brush: js notranslate">> obj.details.color +orange +> obj["details"]["size"] +12 +</pre> + +<h2 id="Array_matrici">Array (matrici)</h2> + +<p>Gli array in JavaScript sono un tipo speciale di oggetto. Essi funzionano in modo molto simile agli oggetti regolari (si può accedere alle proprietà numeriche solo usando la sintassi []) ma hanno una proprietà magica chiamata '<code>length</code>'. Questa è sempre uno in più dell'indice massimo dell'array.</p> + +<p>Il vecchio metodo per creare un array è il seguente:</p> + +<pre class="brush: js notranslate">> var a = new Array(); +> a[0] = "dog"; +> a[1] = "cat"; +> a[2] = "hen"; +> a.length +3 +</pre> + +<p>Una notazione più conveniente è l'utilizzo di una array letterale:</p> + +<pre class="brush: js notranslate">> var a = ["dog", "cat", "hen"]; +> a.length +3 +</pre> + +<p><span id="result_box" lang="it"><span class="alt-edited hps">Lasciare una</span> <span class="hps">virgola finale</span> <span class="hps">al termine di</span> <span class="alt-edited hps">un array letterale</span> <span class="alt-edited hps">è incompatibile</span> <span class="hps">tra i browser</span><span>,</span> <span class="alt-edited hps">quindi</span> <span class="alt-edited hps">non fatelo</span><span>.</span></span></p> + +<p>Nota che <code>array.length</code> non è necessariamente il numero di elementi nell'array. Considera il seguente esempio:</p> + +<pre class="brush: js notranslate">> var a = ["dog", "cat", "hen"]; +> a[100] = "fox"; +> a.length +101 +</pre> + +<p>Ricorda — la lunghezza dell'array è uno più dell'indice più alto.</p> + +<p>Se si interroga un indice dell'array inesistente, la risposta sarà <code>undefined</code>:</p> + +<pre class="brush: js notranslate">> typeof a[90] +undefined +</pre> + +<p><span id="result_box" lang="it"><span class="hps">Se si prende</span> <span class="hps">in considerazione</span> <span class="hps">quanto sopra</span><span>,</span> <span class="hps">è possibile</span> <span class="hps">scorrere</span> <span class="hps">un array</span> <span class="alt-edited hps">utilizzando le istruzioni </span><span class="hps">seguenti</span><span>:</span></span></p> + +<pre class="brush: js notranslate">for (var i = 0; i < a.length; i++) { + // Do something with a[i] +} +</pre> + +<p><span id="result_box" lang="it"><span class="hps">Questo è</span> <span class="hps">un po' inefficiente</span><span>, poichè si ricerca</span><span class="hps"> la</span> <span class="hps">proprietà length</span><span> una volta</span> <span class="hps">ogni ciclo</span><span>.</span> <span class="hps">Un possibile miglioramento</span> <span class="hps">è questo:</span></span></p> + +<pre class="brush: js notranslate">for (var i = 0, len = a.length; i < len; i++) { + // Do something with a[i] +} +</pre> + +<p>Un modo ancora più simpatico è questo:</p> + +<pre class="brush: js notranslate">for (var i = 0, item; item = a[i++];) { + // Do something with item +} +</pre> + +<p>Qui si stanno impostando due variabili. L'assegnamento nella parte centrale del ciclo <code>for</code> è anche verificato per veridicità — se ha successo, il ciclo continua. Siccome <code>i</code> viene incrementato ogni volta, <span id="result_box" lang="it"><span class="hps">gli elementi dalla matrice</span> <span class="alt-edited hps">saranno assegnati</span> <span class="alt-edited hps">all'elemento</span> <span class="hps">in ordine sequenziale</span><span>. Il ciclo termina quando viene trovato un elemento "falso" </span></span>(come un <code>undefined</code>).</p> + +<p>Nota che questo trucco dovrebbe essere usato solo per gli array che sappiamo non contengano valori "falsi" (array di oggetti o nodi del <a href="/en-US/docs/DOM" title="DOM">DOM</a> per esempio). <span id="result_box" lang="it"><span class="hps">Se</span> <span class="hps">si effettua l'iterazione</span> <span class="hps">dei dati</span> <span class="hps">numerici</span> <span class="hps">che potrebbero includere</span> <span class="hps">uno 0</span>, <span class="hps">o dati</span> <span class="hps">stringa che</span> <span class="alt-edited hps">potrebbero includere</span> <span class="hps">la stringa vuota,</span> <span class="hps">è necessario utilizza l'idioma </span></span><code>i, len</code> in sostituzione.</p> + +<p>Un altro modo per iterare è di utilizzare il ciclo <code><a href="/en-US/docs/JavaScript/Reference/Statements/for...in" title="JavaScript/Reference/Statements/for...in">for...in</a></code>. Nota che se vengono aggiunte nuove proprietà all' <code>Array.prototype</code>, saranno anch'esse iterate da questo ciclo:</p> + +<pre class="brush: js notranslate">for (var i in a) { + // Do something with a[i] +} +</pre> + +<p>Se si vuole accodare un elemento all'array, la maniera più sicura per farlo è questa:</p> + +<pre class="brush: js notranslate">a[a.length] = item; // same as a.push(item); +</pre> + +<p>Poichè <code>a.length</code> è uno in più dell'indice più alto, si può essere sicuri che l'elemento sarà assegnato ad una posizione vuota alla fine dell'array.</p> + +<p>Gli arrays nascono con alcuni metodi:</p> + +<table style="height: 124px; width: 598px;"> + <thead> + <tr> + <th scope="col">Method name</th> + <th scope="col">Description</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>a.toString()</code></td> + <td></td> + </tr> + <tr> + <td><code>a.toLocaleString()</code></td> + <td></td> + </tr> + <tr> + <td><code>a.concat(item[, itemN])</code></td> + <td>Restituisce un nuovo array con gli elementi aggiunti ad esso.</td> + </tr> + <tr> + <td><code>a.join(sep)</code></td> + <td></td> + </tr> + <tr> + <td><code>a.pop()</code></td> + <td>Rimuove e restituisce l'ultimo elemento.</td> + </tr> + <tr> + <td><code>a.push(item[, itemN])</code></td> + <td><code>Push</code> aggiunge uno o più elementi alla fine.</td> + </tr> + <tr> + <td><code>a.reverse()</code></td> + <td></td> + </tr> + <tr> + <td><code>a.shift()</code></td> + <td></td> + </tr> + <tr> + <td><code>a.slice(start, end)</code></td> + <td>Restituisce un sub-array.</td> + </tr> + <tr> + <td><code>a.sort([cmpfn])</code></td> + <td>Riceve una funzione di comparazione opzionale.</td> + </tr> + <tr> + <td><code>a.splice(start, delcount[, itemN])</code></td> + <td>Permette di modificare un array cancellando una sezione e sostituendola con più elementi.</td> + </tr> + <tr> + <td><code>a.unshift([item])</code></td> + <td>Antepone elementi all'inizio dell'array</td> + </tr> + </tbody> +</table> + +<h2 id="Funzioni">Funzioni</h2> + +<p><span id="result_box" lang="it"><span class="hps">Insieme</span> <span class="hps">con gli oggetti</span><span>, le funzioni</span> <span class="hps">sono la componente principale</span> <span class="hps">nella comprensione</span> <span class="alt-edited hps">di JavaScript</span><span>.</span> <span class="hps">La funzione</span> <span class="alt-edited hps">più elementare</span> <span class="hps">non potrebbe essere</span> <span class="hps">molto più semplice</span><span>:</span></span></p> + +<pre class="brush: js notranslate">function add(x, y) { + var total = x + y; + return total; +} +</pre> + +<p><span id="result_box" lang="it"><span class="hps">Ciò dimostra</span> <span class="hps">tutto quello che c'è</span> <span class="alt-edited hps">da sapere sulle</span> <span class="hps">funzioni di base</span><span>.</span></span> Una funzione JavaScript può ricevere 0 (zero) o più parametri. Il corpo della funzione può contenere tutte le istruzioni che si desidera, e può dichiarare le proprie variabili che saranno locali alla stessa. L'istruzione <code>return</code> può essere usata per restituire un valore in qualsiasi momento, terminando la funzione. Se non viene utilizzata l'istruzione return (oppure viene restituito un valore vuoto o indefinito), JavaScript restituisce <code>undefined</code>.</p> + +<p><span id="result_box" lang="it"><span class="hps">I</span> <span class="hps">parametri denominati</span> <span class="alt-edited hps">risultano</span> <span class="alt-edited hps">più simili al</span><span class="alt-edited hps">le linee guida</span> <span class="hps">di ogni altra cosa</span><span>.</span> <span class="hps">È possibile</span> <span class="hps">chiamare una funzione</span> <span class="hps">senza passare</span> <span class="hps">i parametri</span> <span class="hps">che si aspetta</span><span>,</span> <span class="hps">nel qual caso</span> <span class="alt-edited hps">saranno impostati</span> <span class="hps">su </span></span><code>undefined</code>.</p> + +<pre class="brush: js notranslate">> add() +NaN // You can't perform addition on undefined +</pre> + +<p><span id="result_box" lang="it"><span class="hps">È anche possibile passare</span> <span class="alt-edited hps">più</span> <span class="hps">argomenti</span> <span class="alt-edited hps">di quelli che la funzione</span> <span class="hps">si aspetta</span><span>:</span></span></p> + +<pre class="brush: js notranslate">> add(2, 3, 4) +5 // added the first two; 4 was ignored +</pre> + +<p><span id="result_box" lang="it"><span class="hps">Questo può sembrare</span> <span class="hps">un po' sciocco</span><span>,</span> <span class="hps">ma le funzioni</span> <span class="hps">hanno accesso a</span> <span class="hps">una variabile aggiuntiva</span> <span class="hps">all'interno del loro corpo</span> <span class="hps">chiamata</span></span> <a href="/en-US/docs/JavaScript/Reference/Functions_and_function_scope/arguments" title="JavaScript/Reference/Functions_and_function_scope/arguments"><code>argomenti</code></a>, che è un oggetto simil array che detiene tutti i valori passati alla funzione. Riscriviamo la funzione somma per ricevere tutti i valori che vogliamo:</p> + +<pre class="brush: js notranslate">function add() { + var sum = 0; + for (var i = 0, j = arguments.length; i < j; i++) { + sum += arguments[i]; + } + return sum; +} + +> add(2, 3, 4, 5) +14 +</pre> + +<p>Questo, però, non è realmente più utile che scrivere <code>2 + 3 + 4 + 5</code>. Creiamo una funzione per il calcolo della media:</p> + +<pre class="brush: js notranslate">function avg() { + var sum = 0; + for (var i = 0, j = arguments.length; i < j; i++) { + sum += arguments[i]; + } + return sum / arguments.length; +} +> avg(2, 3, 4, 5) +3.5 +</pre> + +<p><span id="result_box" lang="it"><span class="alt-edited hps">Questa</span> <span class="alt-edited hps">è piuttosto utile</span><span>,</span> <span class="hps">ma introduce</span> <span class="hps">un nuovo problema</span><span>.</span></span> La funzione <code>avg()</code> riceve una lista di argomenti separati da una virgola — <span id="result_box" lang="it"><span class="hps">ma</span> <span class="hps">cosa succede se</span> <span class="hps">si vuole</span> <span class="hps">trovare la media</span> <span class="hps">di un array</span><span>?</span></span> <span class="short_text" id="result_box" lang="it"><span class="alt-edited hps">Si potrebbe semplicemente</span> <span class="hps">riscrivere la</span> <span class="hps">funzione come segue:</span></span></p> + +<pre class="brush: js notranslate">function avgArray(arr) { + var sum = 0; + for (var i = 0, j = arr.length; i < j; i++) { + sum += arr[i]; + } + return sum / arr.length; +} +> avgArray([2, 3, 4, 5]) +3.5 +</pre> + +<p><span id="result_box" lang="it"><span class="hps">Ma sarebbe</span> <span class="hps">bello essere in</span> <span class="hps">grado di riutilizzare la</span> <span class="hps">funzione che</span> <span class="hps">abbiamo già creato</span><span>.</span></span> Fortunatamente, JavaScript permette di chiamare una funzione e di chiamarla con un array arbitrario di argomenti, usando il metodo <a href="/en-US/docs/JavaScript/Reference/Global_Objects/Function/apply" title="JavaScript/Reference/Global_Objects/Function/apply"><code>apply()</code></a> di qualunque oggetto di funzione.</p> + +<pre class="brush: js notranslate">> avg.apply(null, [2, 3, 4, 5]) +3.5 is the array to use as arguments; the first will be discussed later on. This emphasizes the fact that functions are objects too. +</pre> + +<p>JavaScript permette la creazione di funzioni anonime.</p> + +<pre class="brush: js notranslate">var avg = function() { + var sum = 0; + for (var i = 0, j = arguments.length; i < j; i++) { + sum += arguments[i]; + } + return sum / arguments.length; +} +</pre> + +<p>Questa è semanticamente equivalente alla forma <code>function avg()</code>. Essa è estremamente potente, in quando consente di definire una funzione ovunque si possa normalmente inserire un espressione. <span id="result_box" lang="it"><span class="alt-edited hps">Questo consente</span> <span class="alt-edited hps">ogni sorta di</span> <span class="alt-edited hps">trucco intelligente</span><span>.</span> <span class="hps">Ecco un</span> <span class="hps">modo</span> <span class="hps">di "nascondere"</span> <span class="hps">alcune variabili</span> <span class="hps">locali</span> <span class="hps">- come</span> in <span class="alt-edited hps">un ambito di blocco </span><span class="hps">in C</span><span>:</span></span></p> + +<pre class="brush: js notranslate">> var a = 1; +> var b = 2; +> (function() { + var b = 3; + a += b; +})(); +> a +4 +> b +2 +</pre> + +<p><span id="result_box" lang="it"><span class="hps">JavaScript</span> <span class="hps">consente di</span> <span class="hps">chiamare le funzioni</span> <span class="hps">in modo ricorsivo</span><span>.</span> <span class="hps">Ciò è particolarmente utile</span> <span class="hps">per affrontare</span> <span class="hps">le strutture ad albero</span><span>, come</span> ad esempio nel </span><a href="/en-US/docs/DOM" title="DOM">DOM</a> del browser.</p> + +<pre class="brush: js notranslate">function countChars(elm) { + if (elm.nodeType == 3) { // TEXT_NODE + return elm.nodeValue.length; + } + var count = 0; + for (var i = 0, child; child = elm.childNodes[i]; i++) { + count += countChars(child); + } + return count; +} +</pre> + +<p><span id="result_box" lang="it"><span class="hps">Questo</span> <span class="hps">mette in evidenza</span> <span class="hps">un potenziale problema</span> <span class="hps">con le funzioni</span> <span class="hps">anonime</span></span>: come fare a richiamarle ricorsivamente se non hanno un nome? La risposta si trova con <s>l'oggetto <code>arguments</code>, che oltre ad agire come una lista di argomenti, fornisce anche una propietà chiamata <code>arguments.callee</code></s>. L'uso della <code>arguments.callee</code> è deprecato e anche disabilitato nel modo strict (rigoroso). In sostituzione si devono utilizzare le "funzioni anonime nominate" come di seguito:</p> + +<pre class="brush: js notranslate">var charsInBody = (function counter(elm) { + if (elm.nodeType == 3) { // TEXT_NODE + return elm.nodeValue.length; + } + var count = 0; + for (var i = 0, child; child = elm.childNodes[i]; i++) { + count += counter(child); + } + return count; +})(document.body); +</pre> + +<p><span id="result_box" lang="it"><span class="hps">Il nome fornito</span> <span class="hps">a una funzione anonima</span> <span class="hps">come sopra</span> <span class="atn hps">è (</span><span>o almeno dovrebbe</span> <span class="hps">essere)</span> <span class="alt-edited hps">disponibile solo</span> <span class="alt-edited hps">nell'ambito</span> <span class="hps">stesso</span> <span class="hps">della funzione.</span> <span class="hps">Questo</span> <span class="hps">consente</span> <span class="hps">sia</span> <span class="hps">più</span> <span class="hps">ottimizzazioni</span> <span class="alt-edited hps">da svolgere</span> <span class="alt-edited hps">da parte del motore</span> <span class="alt-edited hps">sia</span> <span class="hps">un codice</span> <span class="hps">più leggibile</span><span>.</span></span></p> + +<h2 id="Oggetti_personalizzati">Oggetti personalizzati</h2> + +<div class="note"><strong>Nota:</strong> Per una discussione più dettagliata della programmazione orientata agli oggetti, vedi <a href="/en-US/docs/JavaScript/Introduction_to_Object-Oriented_JavaScript" title="https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript">Introduzione a JavaScript Orientato agli Oggetti</a>.</div> + +<p>Nella programmazione Object Oriented classica, gli oggetti sono collezioni di dati e metodi che operano su quei dati. JavaScript è un linguaggio basato su prototipi e non contiene l'istruzione classe, così come si trova in C++ o Java. (<span id="result_box" lang="it"><span class="hps">Questo a volte è</span> <span class="hps">fonte di confusione per</span> <span class="hps">i programmatori</span> <span class="hps">abituati</span> <span class="alt-edited hps">ai linguaggi</span> <span class="hps">con una dichiarazione</span> <span class="hps">di classe</span><span>.</span></span>) Al suo posto, JavaScript usa le funzioni come classi. Consideriamo un oggetto persona con i campi nome e cognome. Ci sono due modi di visualizzare il nominativo: come "nome cognome" o come "cognome, nome". Usando le funzioni e gli oggetti che abbiamo visto in precedenza, ecco un modo di ottenere il risultato voluto:</p> + +<pre class="brush: js notranslate">function makePerson(first, last) { + return { + first: first, + last: last + } +} +function personFullName(person) { + return person.first + ' ' + person.last; +} +function personFullNameReversed(person) { + return person.last + ', ' + person.first +} +> s = makePerson("Simon", "Willison"); +> personFullName(s) +Simon Willison +> personFullNameReversed(s) +Willison, Simon +</pre> + +<p>Questo funziona, ma è piuttosto brutto. Si finisce con dozzine di funzioni nel namespace globale. Ciò di cui abbiamo veramente bisogno è un modo per associare una funzione ad un oggetto. Dal momento che le funzioni sono oggetti, questo è facile:</p> + +<pre class="brush: js notranslate">function makePerson(first, last) { + return { + first: first, + last: last, + fullName: function() { + return this.first + ' ' + this.last; + }, + fullNameReversed: function() { + return this.last + ', ' + this.first; + } + } +} +> s = makePerson("Simon", "Willison") +> s.fullName() +Simon Willison +> s.fullNameReversed() +Willison, Simon +</pre> + +<p>Vi è qualcosa che non abbiamo visto prima: la parola chiave '<code><a href="/en-US/docs/JavaScript/Reference/Operators/this" title="JavaScript/Reference/Operators/Special_Operators/this_Operator">this</a></code>'. Usata dentro una funzione, '<code>this</code>' si riferisce all'oggetto corrente. Che cosa significa in realtà è specificato dal modo in cui è stata chiamata tale funzione. Se è stata chiamata usando <a href="/en-US/docs/JavaScript/Reference/Operators/Member_Operators" title="JavaScript/Reference/Operators/Member_Operators">la notazione col punto o la notazione con le parentesi</a> su un oggetto, questo oggetto diventa '<code>this</code>'. Se la notazione col punto non è stata usata per la chiamata, '<code>this</code>' si riferisce all'oggetto globale. Questa è una causa di errori frequente. Ad esempio:</p> + +<pre class="brush: js notranslate">> s = makePerson("Simon", "Willison") +> var fullName = s.fullName; +> fullName() +undefined undefined +</pre> + +<p>Quando chiamiamo <code>fullName()</code>, '<code>this</code>' è legata all'oggetto globale. Dato che non ci sono variabili globali chiamate <code>first</code> o <code>last</code> riceviamo <code>undefined</code> per ognuna delle due.</p> + +<p>Possiamo prendere il vantaggio della parola chiave '<code>this</code>' per migliorare la nostra funzione <code>makePerson</code>:</p> + +<pre class="brush: js notranslate">function Person(first, last) { + this.first = first; + this.last = last; + this.fullName = function() { + return this.first + ' ' + this.last; + } + this.fullNameReversed = function() { + return this.last + ', ' + this.first; + } +} +var s = new Person("Simon", "Willison"); +</pre> + +<p>Abbiamo introdotto un'altra parola chiave: '<code><a href="/en-US/docs/JavaScript/Reference/Operators/new" title="JavaScript/Reference/Operators/Special_Operators/new_Operator">new</a></code>'. <code>new</code> è fortemente correlata a '<code>this</code>'. Quello che fa è creare un oggetto vuoto nuovo di zecca e quindi chiamare la funzione specificata, con '<code>this</code>' impostato sul nuovo oggetto. Le funzioni che sono disegnate per essere richiamate dalla '<code>new</code>' sono chiamate costruttori. La pratica comune è di nominare queste funzioni con la prima lettera maiuscola in modo da ricordarsi di chiamarle con il <code>new</code>.</p> + +<p>I nostri oggetti persona stanno migliorando, ma vi sono ancora alcuni lati brutti in loro. Ogni volta che si crea un oggetto persona, stiamo creando due nuovi oggetti funzione all'interno di esso - non sarebbe meglio se il codice fosse stato condiviso?</p> + +<pre class="brush: js notranslate">function personFullName() { + return this.first + ' ' + this.last; +} +function personFullNameReversed() { + return this.last + ', ' + this.first; +} +function Person(first, last) { + this.first = first; + this.last = last; + this.fullName = personFullName; + this.fullNameReversed = personFullNameReversed; +} +</pre> + +<p>Così va meglio: stiamo creando i metodi della funzione una sola volta, e assegnando ad essi i riferimenti all'interno del costruttore. Possiamo fare di meglio? La risposta è sì:</p> + +<pre class="brush: js notranslate">function Person(first, last) { + this.first = first; + this.last = last; +} +Person.prototype.fullName = function() { + return this.first + ' ' + this.last; +} +Person.prototype.fullNameReversed = function() { + return this.last + ', ' + this.first; +} +</pre> + +<p><code>Person.prototype</code> è un oggetto condiviso da tutte le istanze di <code>Person</code>. Essa fa parte di una catena di ricerca (che ha un nome speciale, "catena di prototipi"): ogni volta che si tenta di accedere ad una proprietà di <code>Person</code> che non è impostata, JavaScript controllerà <code>Person.prototype</code> per vedere se quella proprietà esiste al suo interno. Come risultato, qualsiasi valore assegnato a <code>Person.prototype</code> diventa disponibile a tutte le istanze del costruttore per mezzo dell'oggetto <code>this</code>.</p> + +<p>Si tratta di uno strumento incredibilmente potente. JavaScript consente di modificare il prototipo di qualcosa in qualsiasi momento nel programma, il che significa che è possibile aggiungere metodi extra per gli oggetti esistenti in fase di esecuzione:</p> + +<pre class="brush: js notranslate">> s = new Person("Simon", "Willison"); +> s.firstNameCaps(); +TypeError on line 1: s.firstNameCaps is not a function +> Person.prototype.firstNameCaps = function() { + return this.first.toUpperCase() +} +> s.firstNameCaps() +SIMON +</pre> + +<p>È interessante notare che è anche possibile aggiungere le cose al prototipo degli oggetti nativi JavaScript. Aggiungiamo un metodo a <code>String</code> che restituisca la stringa al contrario:</p> + +<pre class="brush: js notranslate">> var s = "Simon"; +> s.reversed() +TypeError on line 1: s.reversed is not a function +> String.prototype.reversed = function() { + var r = ""; + for (var i = this.length - 1; i >= 0; i--) { + r += this[i]; + } + return r; +} +> s.reversed() +nomiS +</pre> + +<p>Il nostro nuovo metodo funziona anche con le stringhe letterali!</p> + +<pre class="brush: js notranslate">> "This can now be reversed".reversed() +desrever eb won nac sihT +</pre> + +<p>Come detto prima, il prototipo fa parte di una catena. La radice di questa catena è <code>Object.prototype</code>, i cui metodi includono <code>toString()</code> — è questo metodo che viene chiamato quando si tenta di rappresentare un oggetto come una stringa. Questo è utile per verificare il nostro oggetto <code>Person</code>:</p> + +<pre class="brush: js notranslate">> var s = new Person("Simon", "Willison"); +> s +[object Object] +> Person.prototype.toString = function() { + return '<Person: ' + this.fullName() + '>'; +} +> s +<Person: Simon Willison> +</pre> + +<p>Ricordate come <code>avg.apply()</code> aveva un primo argomento nullo? Possiamo riesaminarlo adesso. Il primo argomento di <code>apply()</code> è l'oggetto che dovrebbe essere trattato come '<code>this</code>'. Per esempio, qui una semplice implementazione di '<code>new</code>':</p> + +<pre class="brush: js notranslate">function trivialNew(constructor) { + var o = {}; // Create an object + constructor.apply(o, arguments); + return o; +} +</pre> + +<p>Questa non è un'esatta replica di <code>new</code> in quanto non imposta la catena del prototipo<span style="line-height: 1.5;"> (sarebbe difficile da illustrare). Non è una cosa che si usa molto spesso, ma è utile conoscerla. In questo snippet, </span><code style="font-style: normal; line-height: 1.5;">...args</code><span style="line-height: 1.5;"> (puntini inclusi) è chiamato il "</span><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/rest_parameters" style="line-height: 1.5;">rest arguments</a><span style="line-height: 1.5;">" – come indicato dal nome, e contiene il resto degli argomenti. Per ora, questa "feature" è sperimentale e solo disponibile in Firefox; è raccomandato attaccare gli </span><code style="font-style: normal; line-height: 1.5;">arguments</code><span style="line-height: 1.5;"> per ora.</span></p> + +<p><span style="line-height: 1.5;">Chiamare</span></p> + +<pre class="brush: js language-js notranslate" style="padding: 1em 0px 1em 30px; font-size: 14px; white-space: normal; color: rgb(77, 78, 83);"><code class="language-js" style="font-family: Consolas, Monaco, 'Andale Mono', monospace; direction: ltr; white-space: pre;"><span class="keyword token" style="color: #0077aa;">var</span> bill <span class="operator token" style="background: rgba(255, 255, 255, 0.498039); color: #a67f59;">=</span> <span class="function token" style="color: #dd4a68;">trivialNew<span class="punctuation token" style="color: #999999;">(</span></span>Person<span class="punctuation token" style="color: #999999;">,</span> <span class="string token" style="color: #669900;">"William"</span><span class="punctuation token" style="color: #999999;">,</span> <span class="string token" style="color: #669900;">"Orange"</span><span class="punctuation token" style="color: #999999;">)</span><span class="punctuation token" style="color: #999999;">;</span></code></pre> + +<div class="line-number" style="margin-top: 1em; position: absolute; left: 0px; right: 0px; line-height: inherit; top: 0px; background: 0px 0px;"></div> + +<p>è dunque quasi equivalente a</p> + +<pre class="brush: js language-js notranslate" style="padding: 1em 0px 1em 30px; font-size: 14px; white-space: normal; color: rgb(77, 78, 83);"><code class="language-js" style="font-family: Consolas, Monaco, 'Andale Mono', monospace; direction: ltr; white-space: pre;"><span class="keyword token" style="color: #0077aa; font-style: inherit; font-weight: inherit;">var</span><span style="color: inherit; font-style: inherit; font-weight: inherit;"> bill</span> <span class="operator token" style="background: rgba(255, 255, 255, 0.498039); color: #a67f59;">=</span> <span class="keyword token" style="color: #0077aa;">new</span> <span class="class-name token">Person</span><span class="punctuation token" style="color: #999999;">(</span><span class="string token" style="color: #669900;">"William"</span><span class="punctuation token" style="color: #999999;">,</span> <span class="string token" style="color: #669900;">"Orange"</span><span class="punctuation token" style="color: #999999;">)</span><span class="punctuation token" style="color: #999999;">;</span></code></pre> + +<div class="line-number" style="margin-top: 1em; position: absolute; left: 0px; right: 0px; line-height: inherit; top: 0px; background: 0px 0px;"></div> + +<p><code style="font-style: normal; line-height: 1.5;">apply()</code><span style="line-height: 1.5;"> ha una funzione sorella dal nome </span><a href="/en-US/docs/JavaScript/Reference/Global_Objects/Function/call" style="line-height: 1.5;" title="JavaScript/Reference/Global_Objects/Function/call"><code>call</code></a><span style="line-height: 1.5;">, che di nuovo ti consente di impostare '</span><code style="font-style: normal; line-height: 1.5;">this</code><span style="line-height: 1.5;">' ma prende una lista espansa di argomenti invece che un array.</span></p> + +<pre class="brush: js notranslate">function lastNameCaps() { + return this.last.toUpperCase(); +} +var s = new Person("Simon", "Willison"); +lastNameCaps.call(s); +// Is the same as: +s.lastNameCaps = lastNameCaps; +s.lastNameCaps(); +</pre> + +<h2 id="Inner_functions">Inner functions</h2> + +<p>In JavaScript è consentito dichiarare una funzione all'interno di un'altra funzione. Lo abbiamo già visto prima, nel caso della precedente funzione <code>makePerson()</code>. Un dettaglio importante di funzioni innestate in JavaScript è che esse possono accedere alle variabili della funzione di livello superiore:</p> + +<pre class="brush: js notranslate">function betterExampleNeeded() { + var a = 1; + function oneMoreThanA() { + return a + 1; + } + return oneMoreThanA(); +} +</pre> + +<p>Ciò è di grande utilità per scrivere codice più manutenibile. Se una funzione dipende da una o due altre funzioni che non sono usate in nessuna altra parte del tuo codice, è possibile nidificare quelle funzioni di utilità dentro la funzione che sarà chiamata dall'esterno. Questo riduce il numero di funzioni che si trovano nel "global scope", che è sempre una buona cosa.</p> + +<p>Questa è anche una grande cosa contro il richiamo di variabili globali. Quando si scrive codice complesso si è spesso tentati di usare variabili globali per condividere i valori tra più funzioni — e ciò rende il codice difficile da manutenere. Le funzioni nidificate possono condividere le variabili della funzione padre, così è possibile usare questo meccanismo per accoppiare le funzioni quando serve, senza contaminare il tuo namespace globale — rendi locali le variabili globali per piacere. Questa tecnica dovrebbe essere usata con parsimonia, ma è una capacità utile da avere.</p> + +<h2 id="Closures">Closures</h2> + +<p>Questo ci porta ad una delle più potenti astrazioni che JavaScript ha da offrire — ma anche quella che può generare più confusione. Cosa fa questo codice sotto?</p> + +<pre class="brush: js notranslate">function makeAdder(a) { + return function(b) { + return a + b; + } +} +x = makeAdder(5); +y = makeAdder(20); +x(6) +? +y(7) +? +</pre> + +<p>Il nome della funzione <code>makeAdder</code> dovrebbe essere esplicito: essa può creare delle nuove funzioni 'adder', che, se chiamate con un determinato argomento, lo addizionano all'argomento con il quale sono state create.</p> + +<p>Quello che sta avvenendo qui è praticamente la stessa cosa vista precedentemente con le "inner functions": una funzione definita dentro un'altra funzione ha accesso alle variabili della funzione esterna. La sola differenza è che in questo caso la funzione esterna ha già restituito il suo risultato, e quindi il senso comune sembrerebbe indicare che le sue variabili locali non siano più disponibili. Ma esse esistono ancora — altrimenti le funzioni "adder" non sarebbero capaci di lavorare. Quello che c'è di più è che ci sono due "copie" differenti delle variabili locali di <code>makeAdder</code> — una nella quale <code>a</code> è 5 e una nella quale <code>a</code> è 20. Così il risultato di quelle chiamate di funzione è il seguente:</p> + +<pre class="brush: js notranslate">x(6) // returns 11 +y(7) // returns 27 +</pre> + +<p>Ecco cosa sta effettivamente avvenendo. Quando JavaScript esegue una funzione, viene creato un oggetto con il proprio ambito di visibilità ('scope object') per trattenere le variabili locali di quella funzione. Esso è inizializzato con tutte le variabili passate in ingresso alla funzione come parametri. Ciò è simile all'oggetto globale in cui si trovano tutte le variabili globali e le funzioni, ma con una paio di differenze importanti: primo, un nuovo 'scope object' etichettato è creato ogni volta che una funzione inizia l'esecuzione, e secondo, a differenza dell'oggetto globale (che nei bowser è accessibile come 'window') non si può accedere direttamente a questi 'scope object' dal tuo codice JavaScript. Ad esempio non c'è nessun meccanismo per iterare sulle proprietà dello 'scope object' corrente.</p> + +<p>Quindi, quando <code>makeAdder</code> è chiamato viene creato un oggetto scope con una proprietà: <code>a</code>, che è l'argomento passato alla funzione <code>makeAdder</code> . A questo punto <code>makeAdder</code> restituisce quindi una funzione appena creata. Normalmente il raccoglitore di rifiuti di JavaScript eliminerebbe l'oggetto scope creato per <code>makeAdder</code> , ma la funzione restituita mantiene un riferimento a tale oggetto scope. Di conseguenza l'oggetto scope non verrà eliminato finchè non ci saranno più riferimenti all'oggetto che la funzione <code>makeAdder</code> restituisce.</p> + +<p>Gli oggetti scope formano una catena chiamata 'scope chain', simile alla catena di prototipi, 'prototype chain', del sistema a oggetti di JavaScript.</p> + +<p>Una <strong>closure</strong> è la combinazione di una funzione e dell'oggetto scope in cui è stata creata.</p> + +<p>Le closures ti consentono di salvare lo stato e in quanto tali, possono spesso essere utilizzate al posto degli oggetti. Puoi trovare <a class="external" href="http://stackoverflow.com/questions/111102/how-do-javascript-closures-work" style="line-height: 1.5;">alcune eccellenti introduzioni alle closures</a> (in lingua inglese).</p> + +<h3 id="Memory_leaks">Memory leaks</h3> + +<pre dir="ltr" id="tw-target-text"> Uno sfortunato effetto collaterale delle chiusure è il rendere facile perdere memoria + su Internet Explorer. JavaScript alloca gli oggetti nella memoria al momento della loro + creazione e tale memoria viene recuperata dal browser quando non rimangono riferimenti a un + oggetto. + Gli oggetti forniti dall'host vengono gestiti da quell'ambiente. + + Gli host del browser devono gestire un gran numero di oggetti che rappresentano + la pagina HTML presentata: gli oggetti del DOM. Spetta al browser gestire l'assegnazione e + il recupero di questi. + + Internet Explorer utilizza il proprio schema di raccolta dei rifiuti per questo, + separato dal meccanismo utilizzato da JavaScript. + È l'interazione tra i due che può causare perdite di memoria. + +Una perdita di memoria in IE si verifica ogni volta che viene formato un riferimento circolare +tra un oggetto JavaScript e un oggetto nativo. Considera quanto segue:</pre> + +<pre class="brush: js notranslate">function leakMemory() { + var el = document.getElementById('el'); + var o = { 'el': el }; + el.o = o; +} +</pre> + +<p>Il riferimento circolare formato sopra crea una perdita di memoria;</p> + +<p>IE non libererà la memoria utilizzata da el fino al completo riavvio del browser. Il caso di cui sopra rischia di passare inosservato; le perdite di memoria diventano un problema reale solo nelle applicazioni a esecuzione prolungata o nelle applicazioni che perdono grandi quantità di memoria a causa di grandi strutture di dati o schemi di perdite all'interno dei loop. Le perdite sono raramente così ovvie: spesso la struttura dei dati trapelati può avere molti livelli di riferimenti, oscurando il riferimento circolare. Le chiusure rendono facile creare una perdita di memoria senza volerlo. Considera questo:</p> + +<pre class="brush: js notranslate">function addHandler() { + var el = document.getElementById('el'); + el.onclick = function() { + this.style.backgroundColor = 'red'; + } +} +</pre> + +<p>Il codice precedente imposta l'elemento in modo che diventi rosso quando viene cliccato. Crea anche una perdita di memoria. Perché? Perché il riferimento a el è inavvertitamente catturato nella chiusura creata per la funzione interna anonima. Questo crea un riferimento circolare tra un oggetto JavaScript (la funzione) e un oggetto nativo (el).</p> + +<pre class="script notranslate" style="font-size: 16px;">needsTechnicalReview(); +</pre> + +<p>Esistono numerose soluzioni per questo problema. Il più semplice è non usare la variabile el:</p> + +<pre class="brush: js notranslate">function addHandler(){ + document.getElementById('el').onclick = function(){ + this.style.backgroundColor = 'red'; + } +} +</pre> + +<p>Sorprendentemente, un trucco per rompere i riferimenti circolari introdotti da una chiusura è aggiungere un'altra chiusura:</p> + +<pre class="brush: js notranslate">function addHandler() { + var clickHandler = function() { + this.style.backgroundColor = 'red'; + }; + (function() { + var el = document.getElementById('el'); + el.onclick = clickHandler; + })(); +} +</pre> + +<p>La funzione interna viene eseguita immediatamente, e nasconde il suo contenuto dalla chiusura creata con clickHandler. Un altro buon trucco per evitare le chiusure è rompere i riferimenti circolari durante l'evento window.onunload. Molte librerie di eventi lo faranno per te. Nota che così facendo si disabilita bfcache in Firefox 1.5, quindi non dovresti registrare un listener di scaricamento in Firefox, a meno che tu non abbia altri motivi per farlo.</p> + +<div class="originaldocinfo"> +<h2 id="Original_Document_Information" name="Original_Document_Information">Original Document Information</h2> + +<ul> + <li>Author: <a class="external" href="http://simon.incutio.com/">Simon Willison</a></li> + <li>Last Updated Date: March 7, 2006</li> + <li>Copyright: © 2006 Simon Willison, contributed under the Creative Commons: Attribute-Sharealike 2.0 license.</li> + <li>More information: For more information about this tutorial (and for links to the original talk's slides), see Simon's <a class="external" href="http://simon.incutio.com/archive/2006/03/07/etech">Etech weblog post</a>.</li> +</ul> +</div> |