Revision 350925 of Una reintroduzione al Java Script (Tutorial JS)

  • Slug della versione: JavaScript/Una_reintroduzione_al_JavaScript
  • Titolo della versione: Una reintroduzione al Java Script (Tutorial JS)
  • ID versione: 350925
  • Data di creazione
  • Autore: Nicola_D
  • Versione corrente? No
  • Commento

Contenuto della versione

Introduzione

Perchè una reintroduzione? Perchè  JavaScript ha la ragionevole pretesa di essere il linguaggio di programmazione più frainteso del mondo. Benchè spesso considerato ironicamente come un giocattolo, la sua ingannevole semplicità nasconde alcune potenti caratteristiche. Il 2005 vide il lancio di diverse applicazioni di alto profilo, che mostravano come la conoscenza profonda di questa tecnologia sia un importante abilità per qualunque sviluppatore web.

E' utile iniziare con un accenno alla storia del linguaggio. JavaScript fu creato nel 1995 da Brendan Eich, un ingegnere presso Netscape, e rilasciata per la prima volta con Netscape 2 all'inizio del 1996. Originariamente dove essere chiamato LiveScript, ma fu rinominato in 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. Questa è stata una fonte di confusione da allora.

Microsoft rilasciò una versione più compatibile del linguaggio chiamata JScript con IE 3 alcuni mesi dopo. Netscape sottomise il linguaggio alla Ecma International, un organizzazione europea per gli standard, che risulta nella prima edizione degli standard ECMAScript nel 1997. Lo standard recevette un significativo aggiornamento come ECMAScript edition 3 nel 1999, ed è rimasto più o meno stabile da allora. La quarda edizione fu abbandonata a causa differenze di politiche a proposito della complessità del linguaggio. Molte parti della quarta edizione formano la base del nuovo ECMAScript edizione 5, pubblicato nel dicembre del 2009.

Questa stabilità è una grande notizia per gli sviluppatori, in quanto ha dato alle varie implementazioni diverso tempo per recuperare. Ci si concentrerà quasi esclusivamente sul dialetto dell'edizione 3. Per familiarità continueremo a chiamarlo Javascript dappertutto.

Diversamente dalla maggior parte dei linguaggi di programmazione, il linguaggio JavaScript non ha il concetto di input e output. E' stato disegnato per girare come un linguaggio di scripting in un ambiente ospite, ed è responsabilità dell'ambiente ospite di fornire meccanismi per comunicare con il mondo esterno. L'ambiente ospite più comune è il browser, ma l'interprete JavaScript può essere trovato anche in Adobe Acrobat, Photoshop, motore Widget di Yahoo! , e addirittura in ambienti lato server.

Panoramica

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 da questi linguaggi ricorrono anche in JavaSript. 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.

Cominciamo guardando il blocco di costruzione di qualsiasi linguaggio: i tipi. I programmmi JavaScript manipolano valori, e tutti quei valori appartengono ad un tipo. I tipi JavaScript sono:

... oh, e Undefined (indefiniti) e Null (nulli), che sono leggermente strani. E gli Array, che sono un tipo speciale di oggetto. E Date ed Espressioni regolari, 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:

  • Numeri
  • Stringhe
  • Booleani
  • Oggetti
    • Funzioni
    • Array
    • Date
    • ExpReg
  • Null
  • Undefined

E ci sono anche alcuni tipi nativi di Errori. Comunque, le cose sono molto più semplici se ci atteniamo al primo diagramma

Numeri

I numeri in JavaScript sono in formato 64-bit a doppia precisione valore del IEEE 754, secondo le specifiche. Questo ha qualche interessante conseguenza. Non esiste una cosa come un intero in JavaScript, quindi bisogna stare un pò attenti con la vostra aritmetica, se siete abituati alla matematica in C o Java. Stare attenti a cose come:

0.1 + 0.2 == 0.30000000000000004

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 La Guida Completa sui Numeri JavaScript.

Gli operatori numerici 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 Math per trattare funzioni matematiche più avanzate e costanti:

Math.sin(3.5);
var d = Math.PI * r * r;

E' possibile convertire una stringa in un intero utilizzando la funzione nativa parseInt(). Questo prende la base per la converzione come secondo argomento opzionale, che si dovrebbe fornire sempre:

> parseInt("123", 10)
123
> parseInt("010", 10)
10

Se non si fornisce la base, si possono ricevere risultati inattesi:

> parseInt("010")
8

Questo succede perchè la funzione parseInt ha deciso di trattare la scringa come un ottale a causa del primo 0.

Se si vuole convertire un numero binario in un intero, basta cambiare la base:

> parseInt("11", 2)
3

Similmente, è possibile analizzare numeri in virgola mobile usando la funzione nativa parseFloat() che utilizza sempre la base 10 diversamente dalla cugina parseInt().

E' inoltre possibile utilizzare l'operatore unario + per convertire valori in numeri:

> + "42"
42 

Un valore speciale chiamato NaN (abbreviazione per "Not a Number" - Non un Numero) viene ritornata se la stringa è non numerica:

> parseInt("hello", 10)
NaN

Il NaN è tossico: se viene fornito come imput a qualsiasi operazione matematica, il risultato sarà anch'esso NaN:

> NaN + 5
NaN

E' possibile verificare se NaN usando la funzione nativa isNaN():

> isNaN(NaN)
true

Anche JavaScript ha i valori speciali Infinity-Infinity:

> 1 / 0
Infinity
> -1 / 0
-Infinity

E' possibile analizzare i valori Infinity, -Infinity e NaN usando la funzione nativa isFinite():

> isFinite(1/0)
false
> isFinite(-Infinity)
false
> isFinite(NaN)
false
Nota: Le funzioni parseInt() e parseFloat() analizzano una stringa finchè raggiungono un carattere che è invalido per il formato numerico specificato, quindi ritornano il numero analizzato fino a quel punto. Tuttavia l'operatore "+" converte semplicemente la stringa a NaN se è presente in essa qualche carattere invalido. E' sufficiente provare ad eseguire l'analisi della stringa "10.2abc" con ogni metodi da soli, utilizzando la console e sarà possibile capire meglio le differenze.

Stringhe

Le stringhe in JavaScript sono sequenze di caratteri. Più precisamente, sono sequenze di Caratteri Unicode, con ogni carattere rappresentato da un numero a 16-bit. Questa dovrebbe essere una buona notizia per tutti coloro che hanno avuto a che fare con l'internazionalizzazione.

Se si vuole rappresentare un singolo carattere, occorre semprlicemente utilizzare una stringa di lunghezza 1.

Per trovare la lunghezza di una stringa, accedere la sua proprietà length:

> "hello".length
5

Ecco il nostro primo assaggio degli oggetti JavaScript! E' stato menzionato che le stringhe sono anch'esse oggetti? Ed hanno anche metodi:

> "hello".charAt(0)
h
> "hello, world".replace("hello", "goodbye")
goodbye, world
> "hello".toUpperCase()
HELLO

Altri tipi

JavaScript distingue tra null, che è un oggetto di tipo 'object' che indica un mancanza deliberata di valore, e undefined, che è un oggetto di tipo 'undefined' che indica un valore non inizializzato — che significa, un valore che non è ancora stato assegnato. Parleremo delle variabili più avanti, ma in JavaScript è possibile dichiarare una variabile senza assegnarle un valore. Facendo questo, il tipo della variabile sarà undefined.

JavaScript ha il tipo booleano, con possibili valori true (vero) e false (falso) (entrambi i quali sono parole chiave). Qualunque valore può essere convertito in booleano seguendo le seguenti regole:

  1. false, 0, la stringa vuota (""), NaN, null, e undefined diventano tutti false
  2. tutti gli altri valori diventano true

E' possibile eseguire questa conversione esplicitamente usando la funzione Boolean():

> Boolean("")
false
> Boolean(234)
true

Tuttavia, questo raramente è necessario, JavaScript eseguirà silenziosamente la conversione quando si aspetta un booleano, così come in una istruzione  if (vedi sotto). Per questa ragione, a volte si parla semplicemente di "valori veri" e "valori falsi" valori significativi che diventano true e false, rispettivamente, quando convertiti in booleani. In alternativa, tali valori possono essere chiamati "truthy" e "falsy", rispettivamente.

Le operazioni booleane come && (and logico), || (or logico), e ! (not logico) sono supportate; vedi sotto.

Variabili

Le nuove varibili sono dichiarate in JavaScript utilizzando la parola chiave var:

var a;
var name = "simon";

Se la variabile viene dichiarata senza assegnarle un valore, il suo tipo sarà undefined

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 var in una istruzione composta (ad esempio all'interno di una struttura di controllo if), essa sarà visibile da parte dell'intera funzione.

Operatori

Gli operatori numerici in JavaScript sono +, -, *, /% - che è l'operatore per il resto. I valori sono assegnanti usando =, e vi sono anche le istruzioni di assegnamento composte tipo += e -=. Questi comprimono la forma x = x operatore y.

x += 5
x = x + 5

E' possibile utilizzare ++ e -- per incrementare e decrementare rispettivamente. Questi possono essere usati come operatori prefissi o postfissi.

L'operatore + compie anche la concatenatione di stringhe:

> "hello" + " world"
hello world

Se si somma una stringa ad un numero (o un altro valore) tutto viene convertito dalla prima stringa. Questo esempio potrebbe aiutare a chiarire il tutto:

> "3" + 4 + 5
345
> 3 + 4 + "5"
75

Sommare una stringa vuota ad un altro tipo è un utile maniera per convertirlo.

I confronti in JavaScript possono essere eseguiti usando <, >, <= e >=. 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:

> "dog" == "dog"
true
> 1 == true
true

Per evitare la coercizione di tipo, si utilizza l'operatore triplo uguale:

> 1 === true
false
> true === true
true

Vi sono anche gli operatori !=!== .

JavaScript ha inoltre le opertazioni bit per bit. Se si desidera utilizzarle, sono lì.

Strutture di controllo

JavaScript ha una serie di strutture di controllo simili agli altri linguaggi della famiglia del C. Le istruzioni condizionali sono supportate da if e else (se e altrimenti) che possono essere concatenati insieme se desiderato:

var name = "kittens";
if (name == "puppies") {
  name += "!";
} else if (name == "kittens") {
  name += "!!";
} else {
  name = "!" + name;
}
name == "kittens!!"

JavaScript ha il ciclo while ed il ciclo do-while. Il primo è utile per un ciclo basico; il secondo per i cicli che si vuole essere sicuri che vengano eseguito almeno una volta:

while (true) {
  // an infinite loop!
}

var input;
do {
  input = get_input();
} while (inputIsNotValid(input))

Il ciclo for in JavaScript è lo stesso che in C e Java: esso permette di fornire le informazioni di controllo per il ciclo in una linea singola.

for (var i = 0; i < 5; i++) {
  // Will execute 5 times
}

Gli operatori && e || usano un corto-circuito logico, che significa che quando sono eseguito il secondo operando è dipendente dal primo. Questo è utile per verificare oggetti nulli prima di accedere i lori attributi:

var name = o && o.getName();

Oppure per impostare valori di default:

var name = otherName || "default";

JavaScript ha un operatore ternario per espressioni condizionali:

var allowed = (age > 18) ? "yes" : "no";

L'istruzione switch può essere utilizzata per più diramazioni sulla base di un numero o una stringa:

switch(action) {
    case 'draw':
        drawit();
        break;
    case 'eat':
        eatit();
        break;
    default:
        donothing();
}

Se non viene inserita l'istruzione break, l'esecuzione "naufragherà" nel prossimo livello. Questo è raramente il risultato voluto — in realtà vale la pena in particolare inserire un etichettatura deliberatamente con un commento, se vi vuole aiutare il debug:

switch(a) {
    case 1: // fallthrough
    case 2:
        eatit();
        break;
    default:
        donothing();
}

La clausula default è opzionale. Si possono avere espressioni sia nello switch sia che nel case se si vuole; You can have expressions in both the switch part and the cases if you like; i confronti avvengono tra i due con l'operatore ===:

switch(1 + 3) {
    case 2 + 2:
        yay();
        break;
    default:
        neverhappens();
}

Oggetti

Gli oggetti JavaScript sono semplicemente collezioni di coppie nome-valore. Come tali, essi sono simili a:

  • Dizionari in Python
  • Hashes in Perl e Ruby
  • Hash tables in C e C++
  • HashMaps in Java
  • Array associativi in PHP

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!

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.

Ci sono due modalità di base per creare un oggetto vuoto:

var obj = new Object();

E:

var obj = {};

Entrambe sono semanticamente equivalenti; la seconda è chiamata sintassi letterale dell'oggetto, ed è più convenienete. Questa sintassi è anche la base del formato JSON e dovrebbe essere preferita ogni volta.

Una volta creato, le proprietà di un oggetto possono essere nuovamente accedute in una o due modalità:

obj.name = "Simon";
var name = obj.name;

E...

obj["name"] = "Simon";
var name = obj["name"];

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 parole riservate:

obj.for = "Simon"; // Syntax error, because 'for' is a reserved word
obj["for"] = "Simon"; // works fine

La sintassi dell'oggetto letterale può essere usata per inizializzare un oggetto nella sua interezza:

var obj = {
    name: "Carrot",
    "for": "Max",
    details: {
        color: "orange",
        size: 12
    }
}

Attributi di accesso possono essere concatenati:

> obj.details.color
orange
> obj["details"]["size"]
12

Array

Gli array in JavaScript sono un tipo speciale di oggetto. Essi funzionano in modo molto simile agli oggetti regolari (le proprietà numeriche possono naturalmente essere accedute solo usando la sintassi []) ma hanno una proprietà magica chiamata 'length'. Questa è sempre uno in più dell'indice massimo dell'array.

Il vecchio metodo per creare un array è il seguente:

> var a = new Array();
> a[0] = "dog";
> a[1] = "cat";
> a[2] = "hen";
> a.length
3

Una notazione più conveniente è l'utilizzo di una array letterale:

> var a = ["dog", "cat", "hen"];
> a.length
3

Lasciare una virgola finale al termine di un array letterale è incompatibile tra i browser, quindi non fatelo.

Nota che array.length non è necessariamente il numero di elementi nell'array. Considera il seguente esempio:

> var a = ["dog", "cat", "hen"];
> a[100] = "fox";
> a.length
101

Ricorda — la lunghezza dell'array è uno più dell'indice più alto.

Se si interroga un indice dell'array inesistente, la risposta sarà undefined:

> typeof a[90]
undefined

Se si prende in considerazione quanto sopra, è possibile scorrere un array utilizzando le istruzioni seguenti:

for (var i = 0; i < a.length; i++) {
    // Do something with a[i]
}

Questo è un po' inefficiente, poichè si ricerca la proprietà length una volta ogni ciclo. Un possibile miglioramento è questo:

for (var i = 0, len = a.length; i < len; i++) {
    // Do something with a[i]
}

Un modo ancora più simpatico è questo:

for (var i = 0, item; item = a[i++];) {
    // Do something with item
}

Here we are setting up two variables. The assignment in the middle part of the for loop is also tested for truthfulness — if it succeeds, the loop continues. Since i is incremented each time, items from the array will be assigned to item in sequential order. The loop stops when a "falsy" item is found (such as undefined).

Note that this trick should only be used for arrays which you know do not contain "falsy" values (arrays of objects or DOM nodes for example). If you are iterating over numeric data that might include a 0 or string data that might include the empty string you should use the i, len idiom instead.

Another way to iterate is to use the for...in loop. Note that if someone added new properties to Array.prototype, they will also be iterated over by this loop:

for (var i in a) {
  // Do something with a[i]
}

If you want to append an item to an array, the safest way to do it is like this:

a[a.length] = item;                 // same as a.push(item);

Since a.length is one more than the highest index, you can be assured that you are assigning to an empty position at the end of the array.

Arrays come with a number of methods:

Method name Description
a.toString()  
a.toLocaleString()  
a.concat(item[, itemN]) Returns a new array with the items added on to it.
a.join(sep)  
a.pop() Removes and returns the last item.
a.push(item[, itemN]) Push adds one or more items to the end.
a.reverse()  
a.shift()  
a.slice(start, end) Returns a sub-array.
a.sort([cmpfn]) Takes an optional comparison function.
a.splice(start, delcount[, itemN]) Lets you modify an array by deleting a section and replacing it with more items.
a.unshift([item]) Prepends items to the start of the array.

Functions

Along with objects, functions are the core component in understanding JavaScript. The most basic function couldn't be much simpler:

function add(x, y) {
    var total = x + y;
    return total;
}

This demonstrates everything there is to know about basic functions. A JavaScript function can take 0 or more named parameters. The function body can contain as many statements as you like, and can declare its own variables which are local to that function. The return statement can be used to return a value at any time, terminating the function. If no return statement is used (or an empty return with no value), JavaScript returns undefined.

The named parameters turn out to be more like guidelines than anything else. You can call a function without passing the parameters it expects, in which case they will be set to undefined.

> add()
NaN // You can't perform addition on undefined

You can also pass in more arguments than the function is expecting:

> add(2, 3, 4)
5 // added the first two; 4 was ignored

That may seem a little silly, but functions have access to an additional variable inside their body called arguments, which is an array-like object holding all of the values passed to the function. Let's re-write the add function to take as many values as we want:

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

That's really not any more useful than writing 2 + 3 + 4 + 5 though. Let's create an averaging function:

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

This is pretty useful, but introduces a new problem. The avg() function takes a comma separated list of arguments — but what if you want to find the average of an array? You could just rewrite the function as follows:

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

But it would be nice to be able to reuse the function that we've already created. Luckily, JavaScript lets you call a function and call it with an arbitrary array of arguments, using the apply() method of any function object.

> avg.apply(null, [2, 3, 4, 5])
3.5

The second argument to apply() is the array to use as arguments; the first will be discussed later on. This emphasizes the fact that functions are objects too.

JavaScript lets you create anonymous functions.

var avg = function() {
    var sum = 0;
    for (var i = 0, j = arguments.length; i < j; i++) {
        sum += arguments[i];
    }
    return sum / arguments.length;
}

This is semantically equivalent to the function avg() form. It's extremely powerful, as it lets you put a full function definition anywhere that you would normally put an expression. This enables all sorts of clever tricks. Here's a way of "hiding" some local variables — like block scope in C:

> var a = 1;
> var b = 2;
> (function() {
    var b = 3;
    a += b;
})();
> a
4
> b
2

JavaScript allows you to call functions recursively. This is particularly useful for dealing with tree structures, such as you get in the browser DOM.

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;
}

This highlights a potential problem with anonymous functions: how do you call them recursively if they don't have a name? The answer lies with the arguments object, which in addition to acting as a list of arguments also provides a property called arguments.callee. The arguments.callee usage is deprecated and even disallowed in strict mode. Instead, you should use "named anonymous functions" as below:

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

The name provided to an anonymous function as above is(or at least should be) only available to the function's own scope. This both allows more optimizations to be done by the engine and a more readable code.

Custom objects

Note: For a more detailed discussion of object-oriented programming in JavaScript, see Introduction to Object Oriented JavaScript.

In classic Object Oriented Programming, objects are collections of data and methods that operate on that data. JavaScript is a prototype-based language which contains no class statement, such as is found in C++ or Java. (This is sometimes confusing for programmers accustomed to languages with a class statement.) Instead, JavaScript uses functions as classes. Let's consider a person object with first and last name fields. There are two ways in which the name might be displayed: as "first last" or as "last, first". Using the functions and objects that we've discussed previously, here's one way of doing it:

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

This works, but it's pretty ugly. You end up with dozens of functions in your global namespace. What we really need is a way to attach a function to an object. Since functions are objects, this is easy:

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

There's something here we haven't seen before: the 'this' keyword. Used inside a function, 'this' refers to the current object. What that actually means is specified by the way in which you called that function. If you called it using dot notation or bracket notation on an object, that object becomes 'this'. If dot notation wasn't used for the call, 'this' refers to the global object. This is a frequent cause of mistakes. For example:

> s = makePerson("Simon", "Willison")
> var fullName = s.fullName;
> fullName()
undefined undefined

When we call fullName(), 'this' is bound to the global object. Since there are no global variables called first or last we get undefined for each one.

We can take advantage of the 'this' keyword to improve our makePerson function:

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

We've introduced another keyword: 'new'. new is strongly related to 'this'. What it does is it creates a brand new empty object, and then calls the function specified, with 'this' set to that new object. Functions that are designed to be called by 'new' are called constructor functions. Common practise is to capitalise these functions as a reminder to call them with new.

Our person objects are getting better, but there are still some ugly edges to them. Every time we create a person object we are creating two brand new function objects within it — wouldn't it be better if this code was shared?

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;
}

That's better: we are creating the method functions only once, and assigning references to them inside the constructor. Can we do any better than that? The answer is yes:

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;
}

Person.prototype is an object shared by all instances of Person. It forms part of a lookup chain (that has a special name, "prototype chain"): any time you attempt to access a property of Person that isn't set, JavaScript will check Person.prototype to see if that property exists there instead. As a result, anything assigned to Person.prototype becomes available to all instances of that constructor via the this object.

This is an incredibly powerful tool. JavaScript lets you modify something's prototype at any time in your program, which means you can add extra methods to existing objects at runtime:

> 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

Interestingly, you can also add things to the prototype of built-in JavaScript objects. Let's add a method to String that returns that string in reverse:

> 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

Our new method even works on string literals!

> "This can now be reversed".reversed()
desrever eb won nac sihT

As I mentioned before, the prototype forms part of a chain. The root of that chain is Object.prototype, whose methods include toString() — it is this method that is called when you try to represent an object as a string. This is useful for debugging our Person objects:

> var s = new Person("Simon", "Willison");
> s
[object Object]
> Person.prototype.toString = function() {
    return '<Person: ' + this.fullName() + '>';
}
> s
<Person: Simon Willison>

Remember how avg.apply() had a null first argument? We can revisit that now. The first argument to apply() is the object that should be treated as 'this'. For example, here's a trivial implementation of 'new':

function trivialNew(constructor) {
    var o = {}; // Create an object
    constructor.apply(o, arguments);
    return o;
}

This isn't an exact replica of new as it doesn't set up the prototype chain. apply() is difficult to illustrate — it's not something you use very often, but it's useful to know about.

apply() has a sister function named call, which again lets you set 'this' but takes an expanded argument list as opposed to an array.

function lastNameCaps() {
    return this.last.toUpperCase();
}
var s = new Person("Simon", "Willison");
lastNameCaps.call(s);
// Is the same as:
s.lastNameCaps = lastNameCaps;
s.lastNameCaps();

Inner functions

JavaScript function declarations are allowed inside other functions. We've seen this once before, with an earlier makePerson() function. An important detail of nested functions in JavaScript is that they can access variables in their parent function's scope:

function betterExampleNeeded() {
    var a = 1;
    function oneMoreThanA() {
        return a + 1;
    }
    return oneMoreThanA();
}

This provides a great deal of utility in writing more maintainable code. If a function relies on one or two other functions that are not useful to any other part of your code, you can nest those utility functions inside the function that will be called from elsewhere. This keeps the number of functions that are in the global scope down, which is always a good thing.

This is also a great counter to the lure of global variables. When writing complex code it is often tempting to use global variables to share values between multiple functions — which leads to code that is hard to maintain. Nested functions can share variables in their parent, so you can use that mechanism to couple functions together when it makes sense without polluting your global namespace — 'local globals' if you like. This technique should be used with caution, but it's a useful ability to have.

Closures

This leads us to one of the most powerful abstractions that JavaScript has to offer — but also the most potentially confusing. What does this do?

function makeAdder(a) {
    return function(b) {
        return a + b;
    }
}
x = makeAdder(5);
y = makeAdder(20);
x(6)
?
y(7)
?

The name of the makeAdder function should give it away: it creates new 'adder' functions, which when called with one argument add it to the argument that they were created with.

What's happening here is pretty much the same as was happening with the inner functions earlier on: a function defined inside another function has access to the outer function's variables. The only difference here is that the outer function has returned, and hence common sense would seem to dictate that its local variables no longer exist. But they do still exist — otherwise the adder functions would be unable to work. What's more, there are two different "copies" of makeAdder's local variables — one in which a is 5 and one in which a is 20. So the result of those function calls is as follows:

x(6) // returns 11
y(7) // returns 27

Here's what's actually happening. Whenever JavaScript executes a function, a 'scope' object is created to hold the local variables created within that function. It is initialised with any variables passed in as function parameters. This is similar to the global object that all global variables and functions live in, but with a couple of important differences: firstly, a brand new scope object is created every time a function starts executing, and secondly, unlike the global object (which in browsers is accessible as window) these scope objects cannot be directly accessed from your JavaScript code. There is no mechanism for iterating over the properties of the current scope object for example.

So when makeAdder is called, a scope object is created with one property: a, which is the argument passed to the makeAdder function. makeAdder then returns a newly created function. Normally JavaScript's garbage collector would clean up the scope object created for makeAdder at this point, but the returned function maintains a reference back to that scope object. As a result, the scope object will not be garbage collected until there are no more references to the function object that makeAdder returned.

Scope objects form a chain called the scope chain, similar to the prototype chain used by JavaScript's object system.

A closure is the combination of a function and the scope object in which it was created.

Closures let you save state — as such, they can often be used in place of objects.

Memory leaks

An unfortunate side effect of closures is that they make it trivially easy to leak memory in Internet Explorer. JavaScript is a garbage collected language — objects are allocated memory upon their creation and that memory is reclaimed by the browser when no references to an object remain. Objects provided by the host environment are handled by that environment.

Browser hosts need to manage a large number of objects representing the HTML page being presented — the objects of the DOM. It is up to the browser to manage the allocation and recovery of these.

Internet Explorer uses its own garbage collection scheme for this, separate from the mechanism used by JavaScript. It is the interaction between the two that can cause memory leaks.

A memory leak in IE occurs any time a circular reference is formed between a JavaScript object and a native object. Consider the following:

function leakMemory() {
    var el = document.getElementById('el');
    var o = { 'el': el };
    el.o = o;
}

The circular reference formed above creates a memory leak; IE will not free the memory used by el and o until the browser is completely restarted.

The above case is likely to go unnoticed; memory leaks only become a real concern in long running applications or applications that leak large amounts of memory due to large data structures or leak patterns within loops.

Leaks are rarely this obvious — often the leaked data structure can have many layers of references, obscuring the circular reference.

Closures make it easy to create a memory leak without meaning to. Consider this:

function addHandler() {
    var el = document.getElementById('el');
    el.onclick = function() {
        this.style.backgroundColor = 'red';
    }
}

The above code sets up the element to turn red when it is clicked. It also creates a memory leak. Why? Because the reference to el is inadvertently caught in the closure created for the anonymous inner function. This creates a circular reference between a JavaScript object (the function) and a native object (el).

needsTechnicalReview();

There are a number of workarounds for this problem. The simplest is not to use the el variable:

function addHandler(){
    document.getElementById('el').onclick = function(){
        this.style.backgroundColor = 'red';
    }
}

Surprisingly, one trick for breaking circular references introduced by a closure is to add another closure:

function addHandler() {
    var clickHandler = function() {
        this.style.backgroundColor = 'red';
    };
    (function() {
        var el = document.getElementById('el');
        el.onclick = clickHandler;
    })();
}

The inner function is executed straight away, and hides its contents from the closure created with clickHandler.

Another good trick for avoiding closures is breaking circular references during the window.onunload event. Many event libraries will do this for you. Note that doing so disables bfcache in Firefox 1.5, so you should not register an unload listener in Firefox, unless you have other reasons to do so.

Original Document Information

  • Author: Simon Willison
  • Last Updated Date: March 7, 2006
  • Copyright: © 2006 Simon Willison, contributed under the Creative Commons: Attribute-Sharealike 2.0 license.
  • More information: For more information about this tutorial (and for links to the original talk's slides), see Simon's Etech weblog post.

 

Sorgente della versione

<h2 id="Introduzione">Introduzione</h2>
<p>Perchè una reintroduzione? Perchè&nbsp; <a href="/en/JavaScript" title="en/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. Il 2005 vide il lancio di diverse applicazioni di alto profilo, che mostravano come la conoscenza profonda di questa tecnologia sia un importante abilità per qualunque sviluppatore web.</p>
<p>E' utile iniziare con un accenno alla storia del linguaggio. JavaScript fu creato nel 1995 da Brendan Eich, un ingegnere presso Netscape, e rilasciata per la prima volta con Netscape 2 all'inizio del 1996. Originariamente dove essere chiamato LiveScript, ma fu rinominato in 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>Microsoft rilasciò una versione più compatibile del linguaggio chiamata JScript con IE 3 alcuni mesi dopo. Netscape sottomise il linguaggio alla <a class="external" href="http://www.ecma-international.org/">Ecma International</a>, un organizzazione europea per gli standard, che risulta nella prima edizione degli standard <a href="/en/JavaScript/Language_Resources" title="en/ECMAScript">ECMAScript</a> nel 1997. Lo standard recevette 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 quarda edizione fu abbandonata a causa differenze di politiche a proposito della complessità del linguaggio. Molte parti della quarta edizione formano la base del nuovo ECMAScript edizione 5, pubblicato nel dicembre del 2009.</p>
<p>Questa stabilità è una grande notizia per gli sviluppatori, in quanto ha dato alle varie implementazioni diverso tempo per recuperare. Ci si concentrerà quasi esclusivamente sul dialetto dell'edizione 3. Per familiarità continueremo a chiamarlo Javascript dappertutto.</p>
<p>Diversamente dalla maggior parte dei linguaggi di programmazione, il linguaggio JavaScript non ha il concetto di input e output. E' stato disegnato per girare come un linguaggio di scripting in un ambiente ospite, ed è responsabilità dell'ambiente ospite di fornire meccanismi per comunicare con il mondo esterno. L'ambiente ospite più comune è il browser, ma l'interprete JavaScript può essere trovato anche in Adobe Acrobat, Photoshop, motore Widget di Yahoo! , e addirittura in ambienti lato server.</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 da questi linguaggi ricorrono anche in JavaSript. 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/Core_JavaScript_1.5_Reference/Global_Objects/Number" title="en/Core_JavaScript_1.5_Reference/Global_Objects/Number">Numeri</a></li>
  <li><a href="/En/Core_JavaScript_1.5_Reference/Global_Objects/String" title="en/Core_JavaScript_1.5_Reference/Global_Objects/String">Stringhe</a></li>
  <li><a href="/en/JavaScript/Reference/Global_Objects/Boolean" title="en/Core_JavaScript_1.5_Reference/Global_Objects/Boolean">Booleani</a></li>
  <li><a href="/en/JavaScript/Reference/Global_Objects/Function" title="en/Core_JavaScript_1.5_Reference/Global_Objects/Function">Funzioni</a></li>
  <li><a href="/en/JavaScript/Reference/Global_Objects/Object" title="en/Core_JavaScript_1.5_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/JavaScript/Reference/Global_Objects/Array" title="en/Core_JavaScript_1.5_Reference/Global_Objects/Array">Array</a>, che sono un tipo speciale di oggetto. E <a href="/en/JavaScript/Reference/Global_Objects/Date" title="en/Core_JavaScript_1.5_Reference/Global_Objects/Date">Date</a> ed <a href="/en/JavaScript/Reference/Global_Objects/RegExp" title="en/Core_JavaScript_1.5_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/JavaScript/Reference/Global_Objects/Error" title="en/Core_JavaScript_1.5_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="hps atn"> 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">
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/JavaScript/Reference/Operators/Arithmetic_Operators" title="en/Core_JavaScript_1.5_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/JavaScript/Reference/Global_Objects/Math" title="en/Core_JavaScript_1.5_Reference/Global_Objects/Math">Math</a> per trattare funzioni matematiche più avanzate e costanti:</p>
<pre class="brush: js">
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/JavaScript/Reference/Global_Objects/parseInt" title="en/Core_JavaScript_1.5_Reference/Global_Functions/parseInt">parseInt()</a></code>. Questo prende la base per la converzione come secondo argomento opzionale, che si dovrebbe fornire sempre:</p>
<pre class="brush: js">
&gt; parseInt("123", 10)
123
&gt; parseInt("010", 10)
10
</pre>
<p>Se non si fornisce la base, si possono ricevere risultati inattesi:</p>
<pre class="brush: js">
&gt; parseInt("010")
8
</pre>
<p>Questo succede perchè la funzione <code>parseInt</code> ha deciso di trattare la scringa 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">
&gt; parseInt("11", 2)
3
</pre>
<p>Similmente, è possibile analizzare numeri in virgola mobile usando la funzione nativa <code><a href="/en/JavaScript/Reference/Global_Objects/parseFloat" title="en/JavaScript/Reference/Global Objects/parseFloat">parseFloat()</a></code> che utilizza sempre la base 10 diversamente dalla cugina <a href="/en/JavaScript/Reference/Global_Objects/parseInt" title="en/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>
&gt; + "42"
42 
</pre>
<p>Un valore speciale chiamato <code><a href="/en/JavaScript/Reference/Global_Objects/NaN" title="en/Core_JavaScript_1.5_Reference/Global_Properties/NaN">NaN</a></code> (abbreviazione per "Not a Number" - Non un Numero) viene ritornata se la stringa è non numerica:</p>
<pre class="brush: js">
&gt; parseInt("hello", 10)
NaN
</pre>
<p>Il <code>NaN</code> è tossico: se viene fornito come imput a qualsiasi operazione matematica, il risultato sarà anch'esso <code>NaN</code>:</p>
<pre class="brush: js">
&gt; NaN + 5
NaN
</pre>
<p>E' possibile verificare se <code>NaN</code> usando la funzione nativa <code><a href="/en/JavaScript/Reference/Global_Objects/isNaN" title="en/Core_JavaScript_1.5_Reference/Global_Functions/isNaN">isNaN()</a></code>:</p>
<pre class="brush: js">
&gt; isNaN(NaN)
true
</pre>
<p>Anche JavaScript ha i valori speciali <code><a href="/en/JavaScript/Reference/Global_Objects/Infinity" title="en/Core_JavaScript_1.5_Reference/Global_Properties/Infinity">Infinity</a></code> e&nbsp; <code>-Infinity</code>:</p>
<pre class="brush: js">
&gt; 1 / 0
Infinity
&gt; -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/JavaScript/Reference/Global_Objects/isFinite" title="en/Core_JavaScript_1.5_Reference/Global_Functions/isFinite">isFinite()</a></code>:</p>
<pre class="brush: js">
&gt; isFinite(1/0)
false
&gt; isFinite(-Infinity)
false
&gt; isFinite(NaN)
false
</pre>
<div class="note">
  <strong>Nota:</strong> Le funzioni <a href="/en/JavaScript/Reference/Global_Objects/parseInt" title="en/JavaScript/Reference/Global Objects/parseInt"><code>parseInt()</code></a> e <code><a href="/en/JavaScript/Reference/Global_Objects/parseFloat" title="en/JavaScript/Reference/Global Objects/parseFloat">parseFloat()</a></code> analizzano una stringa finchè raggiungono un carattere che è invalido per il formato numerico specificato, quindi ritornano 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 metodi 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/JavaScript/Guide/Obsolete_Pages/Unicode" title="en/Core_JavaScript_1.5_Guide/Unicode">Caratteri Unicode</a>, con ogni carattere rappresentato da un numero a 16-bit. <span id="result_box" lang="it"><span class="hps alt-edited">Questa dovrebbe essere</span> <span class="hps alt-edited">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 semprlicemente utilizzare una stringa di lunghezza 1.</p>
<p>Per trovare la lunghezza di una stringa, accedere la sua proprietà <code><a href="/en/JavaScript/Reference/Global_Objects/String/length" title="en/Core_JavaScript_1.5_Reference/Global_Objects/String/length">length</a></code>:</p>
<pre class="brush: js">
&gt; "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/Core_JavaScript_1.5_Reference/Global_Objects/String#Methods" title="en/Core_JavaScript_1.5_Reference/Global_Objects/String#Methods">metodi</a>:</p>
<pre class="brush: js">
&gt; "hello".charAt(0)
h
&gt; "hello, world".replace("hello", "goodbye")
goodbye, world
&gt; "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 — che significa, un valore che non è ancora stato assegnato. Parleremo delle variabili più avanti, ma in JavaScript è possibile dichiarare una variabile senza assegnarle un valore. Facendo questo, il tipo della variabile 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">
&gt; Boolean("")
false
&gt; Boolean(234)
true
</pre>
<p>Tuttavia, questo raramente è necessario, JavaScript eseguirà silenziosamente la conversione quando si aspetta un booleano, così come in una istruzione&nbsp; <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="hps atn">"</span><span>truthy</span><span>"</span> <span class="hps">e</span> <span class="hps atn">"</span><span>falsy</span><span>"</span><span>,</span> <span class="hps">rispettivamente</span><span>.</span></span></p>
<p>Le operazioni booleane come <code>&amp;&amp;</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/JavaScript/Reference/Statements/var" title="en/Core_JavaScript_1.5_Reference/Statements/var">var</a></code>:</p>
<pre class="brush: js">
var a;
var name = "simon";
</pre>
<p>Se la variabile viene dichiarata senza assegnarle un valore, il suo tipo sarà <code>undefined</code>.&nbsp;</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&nbsp; <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">
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/JavaScript/Reference/Operators/String_Operators" title="en/Core_JavaScript_1.5_Reference/Operators/String_Operators">operatore +</a> compie anche la concatenatione di stringhe:</p>
<pre class="brush: js">
&gt; "hello" + " world"
hello world
</pre>
<p>Se si somma una stringa ad un numero (o un altro valore) tutto viene convertito dalla prima stringa. Questo esempio potrebbe aiutare a chiarire il tutto:</p>
<pre class="brush: js">
&gt; "3" + 4 + 5
345
&gt; 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/JavaScript/Reference/Operators/Comparison_Operators" title="en/Core_JavaScript_1.5_Reference/Operators/Comparison_Operators">confronti</a> in JavaScript possono essere eseguiti usando <code>&lt;</code>, <code>&gt;</code>, <code>&lt;=</code> e <code>&gt;=</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">
&gt; "dog" == "dog"
true
&gt; 1 == true
true
</pre>
<p>Per evitare la coercizione di tipo, si utilizza l'operatore triplo uguale:</p>
<pre class="brush: js">
&gt; 1 === true
false
&gt; true === true
true
</pre>
<p>Vi sono anche gli operatori !<code>=</code> e&nbsp; <code>!==</code> .</p>
<p>JavaScript ha inoltre le <a href="/en/JavaScript/Reference/Operators/Bitwise_Operators" title="en/Core_JavaScript_1.5_Reference/Operators/Bitwise_Operators">opertazioni 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">
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 eseguito almeno una volta:</p>
<pre class="brush: js">
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">
for (var i = 0; i &lt; 5; i++) {
  // Will execute 5 times
}
</pre>
<p>Gli operatori <code>&amp;&amp;</code> e <code>||</code> usano un corto-circuito logico, che significa che quando sono eseguito il secondo operando è dipendente dal primo. Questo è utile per verificare oggetti nulli prima di accedere i lori attributi:</p>
<pre class="brush: js">
var name = o &amp;&amp; o.getName();
</pre>
<p>Oppure per impostare valori di default:</p>
<pre class="brush: js">
var name = otherName || "default";
</pre>
<p>JavaScript ha un operatore ternario per espressioni condizionali:</p>
<pre class="brush: js">
var allowed = (age &gt; 18)&nbsp;? "yes"&nbsp;: "no";
</pre>
<p><span id="result_box" lang="it"><span class="hps">L'istruzione switch</span> <span class="hps alt-edited">può essere utilizzata per</span> <span class="hps alt-edited">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">
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>&nbsp;<span class="hps">deliberatamente&nbsp;</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">
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; You can have expressions in both the switch part and the cases if you like; <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">
switch(1 + 3)&nbsp;{
    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">
var obj = new Object();
</pre>
<p>E:</p>
<pre class="brush: js">
var obj = {};
</pre>
<p>Entrambe sono semanticamente equivalenti; la seconda è chiamata sintassi letterale dell'oggetto, ed è più convenienete. Questa sintassi è anche la base del formato JSON e dovrebbe essere preferita ogni volta.</p>
<p>Una volta creato, le proprietà di un oggetto possono essere nuovamente accedute in una o due modalità:</p>
<pre class="brush: js">
obj.name = "Simon";
var name = obj.name;
</pre>
<p>E...</p>
<pre class="brush: js">
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/JavaScript/Reference/Reserved_Words" title="en/Core_JavaScript_1.5_Reference/Reserved_Words">parole riservate</a>:</p>
<pre class="brush: js">
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">
var obj = {
    name: "Carrot",
    "for": "Max",
    details: {
        color: "orange",
        size: 12
    }
}
</pre>
<p><span class="short_text" id="result_box" lang="it"><span class="hps alt-edited">Attributi</span> <span class="hps">di accesso</span> <span class="hps">possono essere concatenati</span></span>:</p>
<pre class="brush: js">
&gt; obj.details.color
orange
&gt; obj["details"]["size"]
12
</pre>
<h2 id="Arrays">Array</h2>
<p>Gli array in JavaScript sono un tipo speciale di oggetto. Essi funzionano in modo molto simile agli oggetti regolari (le proprietà numeriche possono naturalmente essere accedute 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">
&gt; var a = new Array();
&gt; a[0] = "dog";
&gt; a[1] = "cat";
&gt; a[2] = "hen";
&gt; a.length
3
</pre>
<p>Una notazione più conveniente è l'utilizzo di una array letterale:</p>
<pre class="brush: js">
&gt; var a = ["dog", "cat", "hen"];
&gt; a.length
3
</pre>
<p><span id="result_box" lang="it"><span class="hps alt-edited">Lasciare una</span> <span class="hps">virgola finale</span> <span class="hps">al termine di</span> <span class="hps alt-edited">un array letterale</span> <span class="hps alt-edited">è incompatibile</span> <span class="hps">tra i browser</span><span>,</span> <span class="hps alt-edited">quindi</span> <span class="hps alt-edited">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">
&gt; var a = ["dog", "cat", "hen"];
&gt; a[100] = "fox";
&gt; 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">
&gt; 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="hps alt-edited">utilizzando le istruzioni&nbsp;</span><span class="hps">seguenti</span><span>:</span></span></p>
<pre class="brush: js">
for (var i = 0; i &lt; 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">
for (var i = 0, len = a.length; i &lt; len; i++) {
    // Do something with a[i]
}
</pre>
<p>Un modo ancora più simpatico è questo:</p>
<pre class="brush: js">
for (var i = 0, item; item = a[i++];) {
    // Do something with item
}
</pre>
<p>Here we are setting up two variables. The assignment in the middle part of the <code>for</code> loop is also tested for truthfulness — if it succeeds, the loop continues. Since <code>i</code> is incremented each time, items from the array will be assigned to item in sequential order. The loop stops when a "falsy" item is found (such as <code>undefined</code>).</p>
<p>Note that this trick should only be used for arrays which you know do not contain "falsy" values (arrays of objects or <a href="/en/DOM" title="en/DOM">DOM</a> nodes for example). If you are iterating over numeric data that might include a 0 or string data that might include the empty string you should use the <code>i, len</code> idiom instead.</p>
<p>Another way to iterate is to use the <code><a href="/en/JavaScript/Reference/Statements/for...in" title="en/Core_JavaScript_1.5_Reference/Statements/for...in">for...in</a></code> loop. Note that if someone added new properties to <code>Array.prototype</code>, they will also be iterated over by this loop:</p>
<pre class="brush: js">
for (var i in a) {
  // Do something with a[i]
}
</pre>
<p>If you want to append an item to an array, the safest way to do it is like this:</p>
<pre class="brush: js">
a[a.length] = item;                 // same as a.push(item);
</pre>
<p>Since <code>a.length</code> is one more than the highest index, you can be assured that you are assigning to an empty position at the end of the array.</p>
<p>Arrays come with a number of methods:</p>
<table height="124" width="598">
  <thead>
    <tr>
      <th scope="col">Method name</th>
      <th scope="col">Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code>a.toString()</code></td>
      <td>&nbsp;</td>
    </tr>
    <tr>
      <td><code>a.toLocaleString()</code></td>
      <td>&nbsp;</td>
    </tr>
    <tr>
      <td><code>a.concat(item[, itemN])</code></td>
      <td>Returns a new array with the items added on to it.</td>
    </tr>
    <tr>
      <td><code>a.join(sep)</code></td>
      <td>&nbsp;</td>
    </tr>
    <tr>
      <td><code>a.pop()</code></td>
      <td>Removes and returns the last item.</td>
    </tr>
    <tr>
      <td><code>a.push(item[, itemN])</code></td>
      <td><code>Push</code> adds one or more items to the end.</td>
    </tr>
    <tr>
      <td><code>a.reverse()</code></td>
      <td>&nbsp;</td>
    </tr>
    <tr>
      <td><code>a.shift()</code></td>
      <td>&nbsp;</td>
    </tr>
    <tr>
      <td><code>a.slice(start, end)</code></td>
      <td>Returns a sub-array.</td>
    </tr>
    <tr>
      <td><code>a.sort([cmpfn])</code></td>
      <td>Takes an optional comparison function.</td>
    </tr>
    <tr>
      <td><code>a.splice(start, delcount[, itemN])</code></td>
      <td>Lets you modify an array by deleting a section and replacing it with more items.</td>
    </tr>
    <tr>
      <td><code>a.unshift([item])</code></td>
      <td>Prepends items to the start of the array.</td>
    </tr>
  </tbody>
</table>
<h2 id="Functions">Functions</h2>
<p>Along with objects, functions are the core component in understanding JavaScript. The most basic function couldn't be much simpler:</p>
<pre class="brush: js">
function add(x, y) {
    var total = x + y;
    return total;
}
</pre>
<p>This demonstrates everything there is to know about basic functions. A JavaScript function can take 0 or more named parameters. The function body can contain as many statements as you like, and can declare its own variables which are local to that function. The <code>return</code> statement can be used to return a value at any time, terminating the function. If no return statement is used (or an empty return with no value), JavaScript returns <code>undefined</code>.</p>
<p>The named parameters turn out to be more like guidelines than anything else. You can call a function without passing the parameters it expects, in which case they will be set to <code>undefined</code>.</p>
<pre class="brush: js">
&gt; add()
NaN // You can't perform addition on undefined
</pre>
<p>You can also pass in more arguments than the function is expecting:</p>
<pre class="brush: js">
&gt; add(2, 3, 4)
5 // added the first two; 4 was ignored
</pre>
<p>That may seem a little silly, but functions have access to an additional variable inside their body called <a href="/en/JavaScript/Reference/Functions_and_function_scope/arguments" title="En/Core_JavaScript_1.5_Reference/Functions_and_function_scope/arguments"><code>arguments</code></a>, which is an array-like object holding all of the values passed to the function. Let's re-write the add function to take as many values as we want:</p>
<pre class="brush: js">
function add() {
    var sum = 0;
    for (var i = 0, j = arguments.length; i &lt; j; i++) {
        sum += arguments[i];
    }
    return sum;
}

&gt; add(2, 3, 4, 5)
14
</pre>
<p>That's really not any more useful than writing <code>2 + 3 + 4 + 5</code> though. Let's create an averaging function:</p>
<pre class="brush: js">
function avg() {
    var sum = 0;
    for (var i = 0, j = arguments.length; i &lt; j; i++) {
        sum += arguments[i];
    }
    return sum / arguments.length;
}
&gt; avg(2, 3, 4, 5)
3.5
</pre>
<p>This is pretty useful, but introduces a new problem. The <code>avg()</code> function takes a comma separated list of arguments — but what if you want to find the average of an array? You could just rewrite the function as follows:</p>
<pre class="brush: js">
function avgArray(arr) {
    var sum = 0;
    for (var i = 0, j = arr.length; i &lt; j; i++) {
        sum += arr[i];
    }
    return sum / arr.length;
}
&gt; avgArray([2, 3, 4, 5])
3.5
</pre>
<p>But it would be nice to be able to reuse the function that we've already created. Luckily, JavaScript lets you call a function and call it with an arbitrary array of arguments, using the <a href="/en/JavaScript/Reference/Global_Objects/Function/apply" title="en/Core_JavaScript_1.5_Reference/Global_Objects/Function/apply"><code>apply()</code></a> method of any function object.</p>
<pre class="brush: js">
&gt; avg.apply(null, [2, 3, 4, 5])
3.5
</pre>
<p>The second argument to <code>apply()</code> is the array to use as arguments; the first will be discussed later on. This emphasizes the fact that functions are objects too.</p>
<p>JavaScript lets you create anonymous functions.</p>
<pre class="brush: js">
var avg = function() {
    var sum = 0;
    for (var i = 0, j = arguments.length; i &lt; j; i++) {
        sum += arguments[i];
    }
    return sum / arguments.length;
}
</pre>
<p>This is semantically equivalent to the <code>function avg()</code> form. It's extremely powerful, as it lets you put a full function definition anywhere that you would normally put an expression. This enables all sorts of clever tricks. Here's a way of "hiding" some local variables — like block scope in C:</p>
<pre class="brush: js">
&gt; var a = 1;
&gt; var b = 2;
&gt; (function() {
    var b = 3;
    a += b;
})();
&gt; a
4
&gt; b
2
</pre>
<p>JavaScript allows you to call functions recursively. This is particularly useful for dealing with tree structures, such as you get in the browser <a href="/en/DOM" title="en/DOM">DOM</a>.</p>
<pre class="brush: js">
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>This highlights a potential problem with anonymous functions: how do you call them recursively if they don't have a name? The answer lies with the <strike><code>arguments</code> object, which in addition to acting as a list of arguments also provides a property called <code>arguments.callee</code></strike>. The <code>arguments.callee</code> usage is deprecated and even disallowed in strict mode. Instead, you should use "named anonymous functions" as below:</p>
<pre class="brush: js">
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>The name provided to an anonymous function as above is(or at least should be) only available to the function's own scope. This both allows more optimizations to be done by the engine and a more readable code.</p>
<h2 id="Custom_objects">Custom objects</h2>
<div class="note">
  <strong>Note:</strong> For a more detailed discussion of object-oriented programming in JavaScript, see <a href="/en/JavaScript/Introduction_to_Object-Oriented_JavaScript" title="https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript">Introduction to Object Oriented JavaScript</a>.</div>
<p>In classic Object Oriented Programming, objects are collections of data and methods that operate on that data. JavaScript is a prototype-based language which contains no class statement, such as is found in C++ or Java. (This is sometimes confusing for programmers accustomed to languages with a class statement.) Instead, JavaScript uses functions as classes. Let's consider a person object with first and last name fields. There are two ways in which the name might be displayed: as "first last" or as "last, first". Using the functions and objects that we've discussed previously, here's one way of doing it:</p>
<pre class="brush: js">
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
}
&gt; s = makePerson("Simon", "Willison");
&gt; personFullName(s)
Simon Willison
&gt; personFullNameReversed(s)
Willison, Simon
</pre>
<p>This works, but it's pretty ugly. You end up with dozens of functions in your global namespace. What we really need is a way to attach a function to an object. Since functions are objects, this is easy:</p>
<pre class="brush: js">
function makePerson(first, last) {
    return {
        first: first,
        last: last,
        fullName: function() {
            return this.first + ' ' + this.last;
        },
        fullNameReversed: function() {
            return this.last + ', ' + this.first;
        }
    }
}
&gt; s = makePerson("Simon", "Willison")
&gt; s.fullName()
Simon Willison
&gt; s.fullNameReversed()
Willison, Simon
</pre>
<p>There's something here we haven't seen before: the '<code><a href="/en/JavaScript/Reference/Operators/this" title="en/Core_JavaScript_1.5_Reference/Operators/Special_Operators/this_Operator">this</a></code>' keyword. Used inside a function, '<code>this</code>' refers to the current object. What that actually means is specified by the way in which you called that function. If you called it using <a href="/en/JavaScript/Reference/Operators/Member_Operators" title="en/Core_JavaScript_1.5_Reference/Operators/Member_Operators">dot notation or bracket notation</a> on an object, that object becomes '<code>this</code>'. If dot notation wasn't used for the call, '<code>this</code>' refers to the global object. This is a frequent cause of mistakes. For example:</p>
<pre class="brush: js">
&gt; s = makePerson("Simon", "Willison")
&gt; var fullName = s.fullName;
&gt; fullName()
undefined undefined
</pre>
<p>When we call <code>fullName()</code>, '<code>this</code>' is bound to the global object. Since there are no global variables called <code>first</code> or <code>last</code> we get <code>undefined</code> for each one.</p>
<p>We can take advantage of the '<code>this</code>' keyword to improve our <code>makePerson</code> function:</p>
<pre class="brush: js">
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>We've introduced another keyword: '<code><a href="/en/JavaScript/Reference/Operators/new" title="en/Core_JavaScript_1.5_Reference/Operators/Special_Operators/new_Operator">new</a></code>'. <code>new</code> is strongly related to '<code>this</code>'. What it does is it creates a brand new empty object, and then calls the function specified, with '<code>this</code>' set to that new object. Functions that are designed to be called by '<code>new</code>' are called constructor functions. Common practise is to capitalise these functions as a reminder to call them with <code>new</code>.</p>
<p>Our person objects are getting better, but there are still some ugly edges to them. Every time we create a person object we are creating two brand new function objects within it — wouldn't it be better if this code was shared?</p>
<pre class="brush: js">
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>That's better: we are creating the method functions only once, and assigning references to them inside the constructor. Can we do any better than that? The answer is yes:</p>
<pre class="brush: js">
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> is an object shared by all instances of <code>Person</code>. It forms part of a lookup chain (that has a special name, "prototype chain"): any time you attempt to access a property of <code>Person</code> that isn't set, JavaScript will check <code>Person.prototype</code> to see if that property exists there instead. As a result, anything assigned to <code>Person.prototype</code> becomes available to all instances of that constructor via the <code>this</code> object.</p>
<p>This is an incredibly powerful tool. JavaScript lets you modify something's prototype at any time in your program, which means you can add extra methods to existing objects at runtime:</p>
<pre class="brush: js">
&gt; s = new Person("Simon", "Willison");
&gt; s.firstNameCaps();
TypeError on line 1: s.firstNameCaps is not a function
&gt; Person.prototype.firstNameCaps = function() {
    return this.first.toUpperCase()
}
&gt; s.firstNameCaps()
SIMON
</pre>
<p>Interestingly, you can also add things to the prototype of built-in JavaScript objects. Let's add a method to <code>String</code> that returns that string in reverse:</p>
<pre class="brush: js">
&gt; var s = "Simon";
&gt; s.reversed()
TypeError on line 1: s.reversed is not a function
&gt; String.prototype.reversed = function() {
    var r = "";
    for (var i = this.length - 1; i &gt;= 0; i--) {
        r += this[i];
    }
    return r;
}
&gt; s.reversed()
nomiS
</pre>
<p>Our new method even works on string literals!</p>
<pre class="brush: js">
&gt; "This can now be reversed".reversed()
desrever eb won nac sihT
</pre>
<p>As I mentioned before, the prototype forms part of a chain. The root of that chain is <code>Object.prototype</code>, whose methods include <code>toString()</code>&nbsp;— it is this method that is called when you try to represent an object as a string. This is useful for debugging our <code>Person</code> objects:</p>
<pre class="brush: js">
&gt; var s = new Person("Simon", "Willison");
&gt; s
[object Object]
&gt; Person.prototype.toString = function() {
    return '&lt;Person: ' + this.fullName() + '&gt;';
}
&gt; s
&lt;Person: Simon Willison&gt;
</pre>
<p>Remember how <code>avg.apply()</code> had a null first argument? We can revisit that now. The first argument to <code>apply()</code> is the object that should be treated as '<code>this</code>'. For example, here's a trivial implementation of '<code>new</code>':</p>
<pre class="brush: js">
function trivialNew(constructor) {
    var o = {}; // Create an object
    constructor.apply(o, arguments);
    return o;
}
</pre>
<p>This isn't an exact replica of <code>new</code> as it doesn't set up the prototype chain. <code>apply()</code> is difficult to illustrate — it's not something you use very often, but it's useful to know about.</p>
<p><code>apply()</code> has a sister function named <a href="/en/JavaScript/Reference/Global_Objects/Function/call" title="en/Core_JavaScript_1.5_Reference/Global_Objects/Function/call"><code>call</code></a>, which again lets you set '<code>this</code>' but takes an expanded argument list as opposed to an array.</p>
<pre class="brush: js">
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>JavaScript function declarations are allowed inside other functions. We've seen this once before, with an earlier <code>makePerson()</code> function. An important detail of nested functions in JavaScript is that they can access variables in their parent function's scope:</p>
<pre class="brush: js">
function betterExampleNeeded() {
    var a = 1;
    function oneMoreThanA() {
        return a + 1;
    }
    return oneMoreThanA();
}
</pre>
<p>This provides a great deal of utility in writing more maintainable code. If a function relies on one or two other functions that are not useful to any other part of your code, you can nest those utility functions inside the function that will be called from elsewhere. This keeps the number of functions that are in the global scope down, which is always a good thing.</p>
<p>This is also a great counter to the lure of global variables. When writing complex code it is often tempting to use global variables to share values between multiple functions — which leads to code that is hard to maintain. Nested functions can share variables in their parent, so you can use that mechanism to couple functions together when it makes sense without polluting your global namespace — 'local globals' if you like. This technique should be used with caution, but it's a useful ability to have.</p>
<h2 id="Closures">Closures</h2>
<p>This leads us to one of the most powerful abstractions that JavaScript has to offer — but also the most potentially confusing. What does this do?</p>
<pre class="brush: js">
function makeAdder(a) {
    return function(b) {
        return a + b;
    }
}
x = makeAdder(5);
y = makeAdder(20);
x(6)
?
y(7)
?
</pre>
<p>The name of the <code>makeAdder</code> function should give it away: it creates new 'adder' functions, which when called with one argument add it to the argument that they were created with.</p>
<p>What's happening here is pretty much the same as was happening with the inner functions earlier on: a function defined inside another function has access to the outer function's variables. The only difference here is that the outer function has returned, and hence common sense would seem to dictate that its local variables no longer exist. But they <em>do</em> still exist — otherwise the adder functions would be unable to work. What's more, there are two different "copies" of <code>makeAdder</code>'s local variables — one in which <code>a</code> is 5 and one in which <code>a</code> is 20. So the result of those function calls is as follows:</p>
<pre class="brush: js">
x(6) // returns 11
y(7) // returns 27
</pre>
<p>Here's what's actually happening. Whenever JavaScript executes a function, a 'scope' object is created to hold the local variables created within that function. It is initialised with any variables passed in as function parameters. This is similar to the global object that all global variables and functions live in, but with a couple of important differences: firstly, a brand new scope object is created every time a function starts executing, and secondly, unlike the global object (which in browsers is accessible as window) these scope objects cannot be directly accessed from your JavaScript code. There is no mechanism for iterating over the properties of the current scope object for example.</p>
<p>So when <code>makeAdder</code> is called, a scope object is created with one property: <code>a</code>, which is the argument passed to the <code>makeAdder</code> function. <code>makeAdder</code> then returns a newly created function. Normally JavaScript's garbage collector would clean up the scope object created for <code>makeAdder</code> at this point, but the returned function maintains a reference back to that scope object. As a result, the scope object will not be garbage collected until there are no more references to the function object that <code>makeAdder</code> returned.</p>
<p>Scope objects form a chain called the scope chain, similar to the prototype chain used by JavaScript's object system.</p>
<p>A closure is the combination of a function and the scope object in which it was created.</p>
<p>Closures let you save state — as such, they can often be used in place of objects.</p>
<h3 id="Memory_leaks">Memory leaks</h3>
<p>An unfortunate side effect of closures is that they make it trivially easy to leak memory in Internet Explorer. JavaScript is a garbage collected language — objects are allocated memory upon their creation and that memory is reclaimed by the browser when no references to an object remain. Objects provided by the host environment are handled by that environment.</p>
<p>Browser hosts need to manage a large number of objects representing the HTML page being presented — the objects of the <a href="/en/DOM" title="en/DOM">DOM</a>. It is up to the browser to manage the allocation and recovery of these.</p>
<p>Internet Explorer uses its own garbage collection scheme for this, separate from the mechanism used by JavaScript. It is the interaction between the two that can cause memory leaks.</p>
<p>A memory leak in IE occurs any time a circular reference is formed between a JavaScript object and a native object. Consider the following:</p>
<pre class="brush: js">
function leakMemory() {
    var el = document.getElementById('el');
    var o = { 'el': el };
    el.o = o;
}
</pre>
<p>The circular reference formed above creates a memory leak; IE will not free the memory used by <code>el</code> and <code>o</code> until the browser is completely restarted.</p>
<p>The above case is likely to go unnoticed; memory leaks only become a real concern in long running applications or applications that leak large amounts of memory due to large data structures or leak patterns within loops.</p>
<p>Leaks are rarely this obvious — often the leaked data structure can have many layers of references, obscuring the circular reference.</p>
<p>Closures make it easy to create a memory leak without meaning to. Consider this:</p>
<pre class="brush: js">
function addHandler() {
    var el = document.getElementById('el');
    el.onclick = function() {
        this.style.backgroundColor = 'red';
    }
}
</pre>
<p>The above code sets up the element to turn red when it is clicked. It also creates a memory leak. Why? Because the reference to <code>el</code> is inadvertently caught in the closure created for the anonymous inner function. This creates a circular reference between a JavaScript object (the function) and a native object (<code>el</code>).</p>
<pre class="script" style="font-size: 16px;">
needsTechnicalReview();
</pre>
<p>There are a number of workarounds for this problem. The simplest is not to use the <code>el</code> variable:</p>
<pre class="brush: js">
function addHandler(){
    document.getElementById('el').onclick = function(){
        this.style.backgroundColor = 'red';
    }
}
</pre>
<p>Surprisingly, one trick for breaking circular references introduced by a closure is to add another closure:</p>
<pre class="brush: js">
function addHandler() {
    var clickHandler = function() {
        this.style.backgroundColor = 'red';
    };
    (function() {
        var el = document.getElementById('el');
        el.onclick = clickHandler;
    })();
}
</pre>
<p>The inner function is executed straight away, and hides its contents from the closure created with <code>clickHandler</code>.</p>
<p>Another good trick for avoiding closures is breaking circular references during the <code>window.onunload</code> event. Many event libraries will do this for you. Note that doing so disables <a href="/En/Using_Firefox_1.5_caching" title="En/Using_Firefox_1.5_caching">bfcache in Firefox 1.5</a>, so you should not register an <code>unload</code> listener in Firefox, unless you have other reasons to do so.</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>
<p>&nbsp;</p>
Ripristina questa versione