Concetti di base di JavaScript

Introduzione
jQuery è scritto in JavaScript, un linguaggio di programmazione molto ricco ed espressivo.

Il capitolo si rivolge a chi non conosce il linguaggio, e copre i concetti di base e problemi comuni che possono sorgere quando si lavora con esso. Inoltre, la sezione può essere utile a chi utilizza altri linguaggi di programmazione per capire le peculiarità di JavaScript.

Se siete interessati a saperne di più sul linguaggio, si può leggere il libro JavaScript: The Good Parts che Douglas Crockford ha scritto.

Sintassi di base
Comprendere dichiarazioni, nomi di variabile, spaziatura, e altre sintassi di base JavaScript
2.1: Dichiarazione semplice di una variabile
var foo = 'ciao mondo';
2.2: Gli spazi non hanno alcun valore al di fuori delle virgolette
var foo =     'ciao mondo';
2.3: Le parentesi indicano la priorità
2 * 3 + 5;    // ritorna 11; il prodotto si esegue prima
2 * (3 + 5);  // ritorna 16; per le parentesi, la somma si esegue prima
2.4: La tabulazione migliora la lettura del codice, ma non ha un significato speciale
var foo = function() {
    console.log('ciao');
};
Operatori
Operatori di base
Gli operatori di base permettono la manipolazione di valori.
2.5: Concatenazione
var foo = 'ciao';
var bar = 'mondo';

console.log(foo + ' ' + bar); // 'ciao mondo'
2.6: Moltiplicazione e divisione
2 * 3;
2 / 3;
2.7: Incremento e decremento
var i = 1;

var j = ++i;  // incremento anticipato: j è uguale a 2; i è uguale a 2
var k = i++;  // incremento posticipato: k è uguale a 2; i è uguale a 3
Lavorare con i numeri e le stringhe
In JavaScript, quando si lavora con i numeri e con le stringhe può causare risultati imprevisti.
2.8: Somma vs. concatenazione
var foo = 1;
var bar = '2';

console.log(foo + bar);  // errore: la console di debug mostra 12
2.9: Forzare una stringa ad agire come un numero
var foo = 1;
var bar = '2';

// il costruttore 'Number' obbliga alla 
// stringa di comportarsi come un numero
console.log(foo + Number(bar)); // la console di debug mostra 3
Il costruttore Number, quando viene chiamato come una funzione (come nell’esempio) obbliga al suo argomento a comportarsi come un numero. È inoltre possibile utilizzare l’operatore somma unaria, che ritorna lo stesso risultato:
2.10: Forzare una stringa per agire come un numero (somma unaria)
console.log(foo + +bar);
Operatori Logici
Gli operatori logici permettono valutare una serie di operandi utilizzando operazioni AND e OR.
2.11: Operatori Logici AND e OR
var foo = 1;
var bar = 0;
var baz = 2;

foo || bar;   // ritorna 1, il quale è vero (true)
bar || foo;   // ritorna 1, il quale è vero (true)

foo && bar;   // ritorna 0, il quale è falso (false)
foo && baz;   // ritorna 2, il quale è vero (true)
baz && foo;   // ritorna 1, il quale è vero (true)
L’operatore || (OR logico) restituisce il valore del primo operando, se questo è vero, altrimenti restituisce il valore del secondo operando. Se entrambi gli operandi sono falsi restituisce false (falso). L’operatore && (AND logico) restituisce il valore del primo operando se questo è falso, altrimenti restituisce il valore del secondo operando. Quando entrambi i valori sono veri ritorna vero (true), altrimenti restituisce falso.

È possibile consultare la sezione “Elementi Vero e Falso” per ulteriori dettagli su quali valori vengono valutati come true e quali vengono valutati come false.

Talvolta si può notare che alcuni sviluppatori utilizzino questa logica per il controllo del flusso invece di utilizzare la dichiarazione if. Per Esempio:

// fare qualcosa con foo se foo è vero
foo && doSomething(foo);

// stabilire bar uguale a baz se baz è vero;
// caso contrario, stabilire bar uguale al
// valore di createBar()
var bar = baz || createBar();
Questo stile dichiarazione è molto elegante e concisa, ma può essere difficile da leggere (specialmente per i principianti). È per questo si esplicita, per riconoscerlo durante la lettura del codice. Tuttavia, il suo uso non è raccomandato a meno che non si ha dimestichezza con il concetto e il comportamento.

Operatori di Confronto
Gli operatori di confronto consentono di verificare se certi valori sono equivalenti o identiche.
2.12: Operatori di confronto
var foo = 1;
var bar = 0;
var baz = '1';
var bim = 2;

foo == bar;   // ritorna false
foo != bar;   // ritorna true
foo == baz;   // ritorna true; fare attenzione!

foo === baz;             // ritorna false
foo !== baz;             // ritorna true
foo === parseInt(baz);   // ritorna true

foo > bim;    // ritorna false
bim > baz;    // ritorna true
foo <= baz;   // ritorna true
Codice Condizionale
A volte si desidera eseguire un blocco di codice in determinate condizioni. Le strutture di controllo del flusso – attraverso l’uso di istruzioni if ??ed else permettono di farlo.
2.13: Controllo del flusso
var foo = true;
var bar = false;

if (bar) {
    // questo codice non verrà mai eseguito
    console.log('ciao!');
}

if (bar) {
    // questo codice non si eseguirà
} else {
    if (foo) {
        // questo codice si eseguirà
    } else {
        // si eseguirà se foo e bar sono falsi (false)
    }
}

In una linea singola, quando si scrive un’istruzione if, le parentesi non sono strettamente necessari, ma è raccomandato in quanto rende il codice molto più leggibile.

È necessario essere consapevoli di non definire funzioni con lo stesso nome più volte all’interno di istruzioni if/else, giacché si potrebbe ottenere risultati inaspettati.

Elementi Veri e Falsi
Per controllare il flusso correttamente, è importante capire quali tipi di valori sono “veri” e che “false”. A volte, alcuni valori possino sembrare una cosa, ma finiscono per essere un’altra.
2.14: Valori che ritornano il vero true
'0';
'qualunque stringa';
[];  // un array vuoto
{};  // un oggetto vuoto
1;   // qualsiasi numero diverso da zero
2.15: Valori che ritornano il falso false
0;
'';  // una stringa vuota
NaN; // la variabile JavaScript "not-a-number" (non è un numero)
null; // un valore nullo
undefined;  // // fare attenzione -- (undefined) può essere ridefinito
Variabili condizionali utilizzando l'operatore ternario
A volte si desidera impostare il valore di una variabile in funzione a una certa condizione. Per farlo si può utilizzare una dichiarazione if/else, ma in molti casi è più conveniente usare l’operatore ternario. [Definizione:. L’operatore ternario valuta una condizione, se la condizione è vera, restituisce un certo valore, altrimenti restituisce un valore diverso] 2.16: L'operatore ternario

L’operatore ternario può essere utilizzato senza restituire un valore alla variabile, ma questo uso è generalmente sconsigliato.
Dichiarazione Switch
Invece di usare una serie di istruzioni if/else/else if/else, a volte può essere utile usare l’istruzione switch. [Definizione: un’istruzione Switch valuta il valore di una variabile o espressione ed esegue diferenti blocchi di codice a seconda di quel valore.] 2.17: Una dichiarazione Switch
switch (foo) {

    case 'bar':
        alert('il valore è bar');
    break;

    case 'baz':
        alert('il valore è baz');
    break;

    default:
        alert('impostazione predefinita, questo codice verrà eseguito');
    break;

}
Istruzioni switch sono poco utilizzati in JavaScript, perché lo stesso comportamento può essere ottenuto attraverso la creazione di un oggetto, che ha più potenzialità perché si può riutilizzare, usarlo per i test, e così via.
Per Esempio:
var stuffToDo = {
    'bar' : function() {
        alert('il valore è bar');
    },

    'baz' : function() {
        alert('il valore è baz');
    },

    'default' : function() {
        alert('impostazione predefinita, questo codice verrà eseguito');
    }
};

if (stuffToDo[foo]) {
    stuffToDo[foo]();
} else {
    stuffToDo['default']();
}
Più avanti si tratterà il concetto di oggetti.
Cicli
I cicli (loops in inglese) permettono eseguire un blocco di codice un certo numero di volte.
2.18: Cicli
// mostra nella console 'tentativo 0', 'tentativo 1', ..., 'tentativo 4'
for (var i=0; i<5; i++) {
    console.log('tentativo ' + i);
}

Si noti che nell’esempio si utilizza la parola var prima della variabile i, questo significa che detta variabile è all’interno della sua portata, o ambito, (in inglese scope) del ciclo. Più avanti in questo capitolo si esaminerà in modo approfondito il concetto di portata.

Cicli utilizzando FOR
Un ciclo utilizzando for si compone da quattro Stati e ha la seguente struttura:
for ([espressioneIniziale]; [condizione]; [incrementoDellaEspressione])
 [corpoCiclo]
Lo stato espressioneIniziale viene eseguito una solavolta, prima che il ciclo cominci. Questo dà la possibilità di preparare o di dichiarare le variabili.

Lo stato condizione viene eseguita prima di ogni iterazione, e restituisce un valore che decide se il ciclo deve continuare oppure no. Se lo stato condizionale valuta un valore come falso il ciclo si interrompe.

Lo stato incrementoDellaEspressione viene eseguito alla fine di ogni ripetizione e offre l’opportunità di modificare lo stato di variabili importanti. Di solito, questo stato comporta l’incremento o il decremento di un contatore.

Il corpoCiclo è il codice da eseguire in ogni iterazione del ciclo. In genere ci sono più istruzioni che devono essere eseguiti e così li avvolgono in un blocco ({…}).

Un tipico ciclo utilizzando for:
2.19: Un tipico ciclo utilizzando for

for (var i = 0, limit = 100; i < limit; i++) {
    // Questo blocco di codice viene eseguito 100 volte
    console.log('Attualmente a ' + i);
    // Nota: L'ultimo record da visualizzare 
    // nella console sarà "Attualmente a 99"
}
Cicli utilizzando WHILE
Un ciclo utilizzando while è simile ad un’istruzione condizionale if, tranne che il corpo continuerà a funzionare fino a quando la condizione da valutare sia falsa.
for ([espressioneIniziale]; [condizione]; [incrementoDellaEspressione])
 [corpoCiclo]
Un típico bucle utilizzando while:
2.20: Un típico bucle utilizzando while
var i = 0;
while (i < 100) {

    // Questo blocco di codice verrà eseguito 100 volte
    console.log('Attualmente a ' + i);

    i++; // incrementa la variabile i

}
Si può notare che nell’esempio viene incrementato il contatore all’interno del corpo del ciclo, ma è anche possibile combinare la condizione e l’incremento, come illustrato di seguito:
2.21: Ciclo utilizzando while con la combinazione della condizione e l'incremento
var i = -1;
while (++i < 100) {
    // Questo blocco di codice verrà eseguito 100 volte
    console.log('Attualmente a ' + i);
}
la variabile i inizia a -1 e poi utilizza l’incremento anticipato (++i).
Cicli utilizzando do-while
Questo ciclo è come usare while, tranne che il corpo viene eseguito almeno una volta prima che la condizione venga valutata.
do [corpoCiclo] while ([condizione])
2.22: Un ciclo do-while
do {

    // Anche quando la condizione è falsa
    // il corpo del ciclo viene eseguito almeno una volta.

    alert('Ciao!');

} while (false);
Tali cicli sono abbastanza insoliti, perché raramente si ha bisogno di un ciclo che esegua un giro almeno una volta. In entrambi i casi si dovrebbe essere a conoscenza.
Break e Continue
Di solito, la fine dell’esecuzione di un ciclo coinciderà quando la condizione non continui a valutare un valore vero, tuttavia è anche possibile fermare un ciclo utilizzando l’istruzione break all’interno del corpo.
2.23: Fermare un ciclo con break
for (var i = 0; i < 10; i++) {
    if (qualcosa) {
        break;
    }
}
Può anche accadere che si desidera continuare il ciclo senza dover eseguire più dichiarazioni del corpo del ciclo. Questo può essere fatto utilizzando l’istruzione continue.
2.24: Saltare alla seguente iterazione di un ciclo
for (var i = 0; i < 10; i++) {

    if (qualcosa) {
        continue;
    }

    // La seguente dichiarazione sarà eseguita
    // se la condizione 'something' non si compie
    console.log('I have been reached');

}
Parole Riservate
JavaScript ha un numero di “parole riservate”, o parole che sono speciali all’interno dello stesso linguaggio. Si dovrebbe utilizzare queste parole quando si ha bisogno per il suo uso specifico.

  • abstract
  • boolean
  • break
  • byte
  • case
  • catch
  • char
  • class
  • const
  • continue
  • debugger
  • default
  • delete
  • do
  • double
  • else
  • enum
  • export
  • extends
  • final
  • finally
  • float
  • for
  • function
  • goto
  • if
  • implements
  • import
  • in
  • instanceof
  • int
  • interface
  • long
  • native
  • new
  • package
  • private
  • protected
  • public
  • return
  • short
  • static
  • super
  • switch
  • synchronized
  • this
  • throw
  • throws
  • transient
  • try
  • typeof
  • var
  • void
  • volatile
  • while
  • with
Vettori o Matrici
I vettori (in inglese arrays) sono liste di valori a indice zero (in inglese zero-index), cioè il primo elemento della matrice è l’indice 0. sono un modo conveniente per memorizzare un insieme di dati correlati (come stringhe), ma in realtà, un array può includere più tipi di dati, compresi altri array.
2.25: Un vettore semplice
var myArray = [ 'ciao', 'mondo' ];
2.26: Accedere agli elementi dell'array attraverso il suo indice
var myArray = [ 'ciao', 'mondo' ];
2.27: Ottenere il numero di elementi dell'array
var myArray = [ 'ciao', 'mondo' ];
console.log(myArray.length);   // mostra '2' nella console
2.28: Modificare il valore di un elemento di un array
var myArray = [ 'ciao', 'mondo' ];
myArray[1] = 'modificato';

Come mostrato nell’esempio “Modificare il valore di un elemento di un array” è possibile modificare il valore di un elemento di un array, in genere non è consigliabile.
2.29: Aggiungere elementi ad un array

var myArray = [ 'ciao', 'mondo' ];
myArray.push('nuovo');
2.30: Lavorando con gli array
var myArray = [ 'c', 'i', 'a', 'o' ];
var myString = myArray.join('');   // 'ciao'
var mySplit = myString.split('');  // [ 'c', 'i', 'a', 'o' ]
Oggetti
Gli oggetti sono elementi che possono contenere zero o più insiemi di coppie di nomi chiave e valori associati a tale oggetto. I nomi possono essere qualsiasi parola o numero valido. Il valore può essere qualsiasi tipo di valore: un numero, una stringa, un array, una funzione, anche un altro oggetto.

[Definizione: Quando uno dei valori di un oggetto è una funzione, è chiamato come metodo dell’oggetto.] In caso contrario, essi sono chiamati proprietà..

È interessante notare che in JavaScript, quasi tutto è un oggetto – array, funzioni, numeri, anche le stringhe – e tutti possiedono proprietà e metodi.

var myObject = {
    sayHello : function() {
        console.log('ciao');
    },

    myName : 'Rebecca'
};

myObject.sayHello();           // si chiama il metodo sayHello, che 
                               // visualizza sulla console 'Ciao'
console.log(myObject.myName);  // si chiama la proprietà myName, che 
                               // mostra 'Rebecca' nella console
Si noti che quando si creano oggetti letterali, il nome della proprietà può essere qualsiasi identificatore JavaScript, una stringa (racchiusa tra virgolette) o un numero:
var myObject = {
    validIdentifier: 123,
    'qualche stringa': 456,
    99999: 789
};

Gli oggetti letterali possono essere molto utile per l’organizzazione del codice, per maggiori informazioni potete leggere l’articolo (in inglese) Using Objects to Organize Your Code di Rebecca Murphey.

Funzioni
Le funzioni contengono blocchi di codice che viene eseguito ripetutamente. Alle stesse possono essere passati argomenti, e facoltativamente la funzione può restituire un valore.

Le funzioni possono essere creati in diversi modi:
2.32: Dichiarazione di una funzione

function foo() { /* fa qualcosa */ }
2.33: Dichiarare una funzione denominata
var foo = function() { /* fa qualcosa */ }
È preferibile il metodo della funzione denominata a causa di alcuni motivi tecnici profondo. Probabilmente troverete i due metodi quando si revisiona il codice JavaScript.
Utilizzo delle Funzioni
2.34: Una semplice funzione
var greet = function(person, greeting) {
    var text = greeting + ', ' + person;
    console.log(text);
};


greet('Rebecca', 'Ciao');
2.35: Una funzione che restituisce un valore
var greet = function(person, greeting) {
    var text = greeting + ', ' + person;
    return text;
};

console.log(greet('Rebecca','ciao'));
2.36: Una funzione che restituisce un'altra funzione
var greet = function(person, greeting) {
    var text = greeting + ', ' + person;
    return function() { console.log(text); };
};


var greeting = greet('Rebecca', 'Ciao');
greeting();
Funzioni Anonime Autoeseguilili
Un modello comune in JavaScript sono le funzioni anonime autoeseguibili. Questo modello consiste in creare un’espressione di funzione ed immediatamente eseguirla. Lo stesso è utile nei casi in cui non si vuole intervenire nei namespace globale, perché nessuna variabile dichiarata all’interno della funzione è visibile dall’esterno.
2.37: Una funzione anonima autoeseguibile
(function(){
    var foo = 'Ciao mondo';
})();


console.log(foo);   // indefinito (undefined)
Funzioni come Argomenti
In JavaScript, le funzioni sono “cittadini di prima classe” — possono essere assegnati alle variabili o passate ad altre funzioni come argomenti. In jQuery, passare funzioni come argomenti è una pratica molto comune.
2.38: Passare una funzione anonima come argomento
var myFn = function(fn) {
    var result = fn();
    console.log(result);
};

// mostra nella console 'Ciao mondo'
myFn(function() { return 'Ciao mondo'; });   
2.39: Passare una chiamata di funzione come argomento
var myFn = function(fn) {
    var result = fn();
    console.log(result);
};

var myOtherFn = function() {
    return 'Ciao mondo';
};

// mostra nella console 'Ciao mondo'
myFn(myOtherFn);
Determinazione del tipo di variabile
JavaScript offre un modo per verificare il “tipo” (in inglese type) di una variabile. Tuttavia, il risultato può essere fonte di confusione – per Esempio, il tipo di array è un “object”.

Per ciò, è pratica comune usare l’operatore typeof quando si tratta di determinare il tipo di un valore specifico.
2.40: Determinare il tipo tra differenti variabili

var myFunction = function() {
    console.log('ciao');
};

var myObject = {
    foo : 'bar'
};

var myArray = [ 'a', 'b', 'c' ];

var myString = 'ciao;

var myNumber = 3;

typeof myFunction;   // ritorna 'function'
typeof myObject;     // ritorna 'object'
typeof myArray;      // ritorna 'object' -- fare attenzione
typeof myString;     // ritorna 'string';
typeof myNumber;     // ritorna 'number'

typeof null;         // ritorna 'object' -- fare attenzione


if (myArray.push && myArray.slice && myArray.join) {
    // probabilmente è un array
    // (questo stile è chiamato, in inglese, "duck typing")
}

if (Object.prototype.toString.call(myArray) === '[object Array]') {
    // definitivamente è un array;
    // questa è considerata la forma più robusta
    // per determinare se un valore è un array.
}
jQuery fornisce metodi per determinare il tipo di un certo valore. Questi metodi si vedranno più avanti.
La parola chiave this
In JavaScript, come in molti linguaggi di programmazione object-oriented, this è una parola chiave speciale che fa riferimento all’oggetto in cui il metodo viene invocato. Il valore di this viene determinato utilizzando una serie di semplici passi:

  • Se la funzione viene invocata utilizzando Function.call o Function.apply, this avrà il valore del primo argomento passato al metodo. Se l’argomento è nullo (null) o indefinito (undefined), this farà riferimento all’oggetto globale (l’oggetto window);
  • Se la funzione a invocare viene creata utilizzando Function.bind, this sarà il primo argomento che viene passato alla funzione, al momento della sua creazione;
  • Se la funzione è invocata come metodo di un oggetto, this farà riferimento a detto oggetto;
  • Altrimenti, se la funzione viene invocata come una funzione indipendente, non legata ad alcun oggetto, this farà riferimento all’oggetto globale.
2.41: Una funzione invocata utilizzando Function.call
var myObject = {
    sayHello : function() {
        console.log('Ciao! il mio nome è ' + this.myName);
    },

    myName : 'Rebecca'
};

var secondObject = {
    myName : 'Colin'
};

myObject.sayHello();                  
// registra 'Ciao, il mio nome è Rebecca'
myObject.sayHello.call(secondObject); 
// registra 'Ciao, il mio nome è Colin'
2.42: Una función creada utilizando Function.bind
var myName = 'the global object',

    sayHello = function () {
        console.log('Ciao, il mio nome è ' + this.myName);
    },

    myObject = {
        myName : 'Rebecca'
    };

var myObjectHello = sayHello.bind(myObject);

sayHello();       // registra 'Ciao, il mio nome è oggetto globale'
myObjectHello();  // registra 'Ciao, il mio nome è Rebecca'
2.43: Una funzione vincolata ad un oggetto
var myName = 'oggetto globale',

    sayHello = function() {
        console.log('Ciao, il mio nome è ' + this.myName);
    },

    myObject = {
        myName : 'Rebecca'
    },

    secondObject = {
        myName : 'Colin'
    };

myObject.sayHello = sayHello;
secondObject.sayHello = sayHello;

sayHello();               // registra 'Ciao, il mio nome è oggetto globale'
myObject.sayHello();      // registra 'Ciao, il mio nome è Rebecca'
secondObject.sayHello();  // registra 'Ciao, il mio nome è Colin'
A volte, quando si invoca una funzione che si trova all’interno di uno spazio dei nomi (namespace in inglese) ampio, si può essere tentati di salvare il riferimento alla funzione corrente in una variabile più breve ed accessibile. Tuttavia, è importante non farlo nelle istanze dei metodi, giacché possono portare all’esecuzione del codice errato. Per Esempio:
var myNamespace = {
    myObject : {
        sayHello : function() {
            console.log('Ciao, il mio nome è ' + this.myName);
        },

        myName : 'Rebecca'
    }
};

var hello = myNamespace.myObject.sayHello;

hello();  // registra 'Ciao, il mio nome è undefined'
Per evitare che questi errori si verifichino, è necessario fare riferimento all’oggetto dove il metodo e invocato:
var myNamespace = {
    myObject : {
        sayHello : function() {
            console.log('Ciao!, il mio nome è ' + this.myName);
        },

        myName : 'Rebecca'
    }
};

var obj = myNamespace.myObject;

obj.sayHello();  // registra 'Ciao!, il mio nome è Rebecca'

Ambito
“L’ambito” (scope in inglese) si riferisce a variabili che sono disponibili in un blocco di codice in un dato tempo. La mancanza di comprensione di questo concetto può essere un’esperienza frustrante durante la depurazione.

Quando una variabile viene dichiarata all’interno di una funzione utilizzando la parola chiave var, è disponibile solo per il codice all’interno della funzione – tutto il codice al di fuori della funzione non può accedere alla variabile. D’altra parte, le funzioni definite all’interno della funzione potranno accedere alla variabile dichiarata.

Le variabili dichiarate all’interno della funzione senza la parola chiave var non rimangono nell’ambito di applicazione della stessa funzione – JavaScript cercherà il luogo dove la variabile è stata precedentemente dichiarata, e nel caso che non sia stata dichiarata, sarà definita nell’ambito globale, il quale può portare a risultati inattesi;
2.44: Le funzioni hanno accesso alle variabili definite all'interno dello stesso ambito

var foo = 'Ciao';

var sayHello = function() {
    console.log(foo);
};

sayHello();         // mostra nella console 'Ciao'
console.log(foo);   // mostra anche nella console 'Ciao'
2.45: Il codice esterno non può accedere alla variabile definita all'interno della funzione
var sayHello = function() {
    var foo = 'Ciao';
    console.log(foo);
};

sayHello();         // mostra nella console 'Ciao'
console.log(foo);   // non mostra niente nella console
2.46: Variabili con nomi identici ma diversi valori possono esistere in diversi ambiti
var foo = 'mondo';

var sayHello = function() {
    var foo = 'ciao';
    console.log(foo);
};

sayHello();         // mostra nella console 'ciao'
console.log(foo);   // mostra nella console 'mondo'
var myFunction = function() {
    var foo = 'Ciao';

    var myFn = function() {
        console.log(foo);
    };

    foo = 'mondo';

    return myFn;
};

var f = myFunction();
f();  // registra 'mondo' -- errore
2.48: Ambito folle
// a self-executing anonymous function
(function() {
    var baz = 1;
    var bim = function() { alert(baz); };
    bar = function() { alert(baz); };
})();

console.log(baz);  // La console non mostra nulla,
        // visto che baz è definita nell'ambito
        // della funzione anonima
 
bar();  // bar è definita al di fuori della funzione
        // anonima dopo essere stata dichiarata senza la
        // parola chiave var; inoltre, come è stata
        // definita all'interno della stessa portata di
        // baz, è possibile interrogare il valore del baz,
        // anche se questa sia definita all'interno
        // della portata della funzione anonima
 
bim();  // bim non è definito per essere accessibile
        // al di fuori della funzione anonima,
        // quindi viene visualizzato un errore
Chiusure
Le chiusure (closures in inglese) sono un’estensione del concetto di ambito (scope) – funzioni che hanno accesso alle variabili che sono disponibili all’interno dell’ambito in cui è stata creata la funzione. Se questo concetto è confuso, non preoccuparsi: si capisce meglio attraverso degli esempi.

Nell’sempio 2.47 il modo in cui le funzioni hanno accesso per cambiare il valore delle variabili. Lo stesso comportamento si verifica nelle funzioni create all’interno dei cicli – la funzione “osserva” il cambiamento nella variabile, anche dopo che la funzione sia stata definita, risultando che ad ogni click appaia una finestra di avviso mostrando il valore 5.
2.49: Come impostare il valore di i?

/* questo non si comporta come desiderato */
/* ogni click visualizzerà una finestra di avviso con il valore 5 */
for (var i=0; i<5; i++) {
    $('<p>click me</p>').appendTo('body').click(function() {
        alert(i);
    });
}
2.50: Impostare il valore di i utilizzando una chiusura
/* soluzione: "clausurare" il valor di i all'interno di createFunction */
var createFunction = function(i) {
    return function() { alert(i); };
};

for (var i=0; i<5; i++) {
    $('<p>click me</p>').appendTo('body').click(createFunction(i));
}
Le chiusure possono anche essere utilizzate per risolvere i problemi con la parola chiave this, la quale è unica per ogni ambito.
2.51: Utilizzando una chiusura per accedere simultaneamente ad istanze di oggetti interni ed esterni
var outerObj = {
    myName : 'esterno',
    outerFunction : function () {

        // fornisce un riferimento allo stesso oggetto outerObj 
        // da utilizzare all'interno di innerFunction
        var self = this;

        var innerObj = {
            myName : 'interno',
            innerFunction : function () {
                console.log(self.myName, this.myName); 
                // registra 'esterno interno'
            }
        };

        innerObj.innerFunction();

        console.log(this.myName); 
        // registra 'esterno'
    }
};

outerObj.outerFunction();
Questo meccanismo può essere utile quando si lavora con funzioni di richiamo o retro-chiamate (callbacks in inglese). Tuttavia, in questi casi è preferibile usare Function.bind per evitare qualunque sovraccarico associatoall’ambito (scope).