JavaScript - Chiusure (Closures)

Ciao a tutti, futuri superstar del coding! ? Oggi ci imbarcheremo in un viaggio emozionante nel mondo delle chiusure di JavaScript. Non preoccupatevi se questo sembra un po' intimidatorio - vi prometto che alla fine di questo tutorial, sarete esperti di chiusure! Allora, prendetevi la vostra bevanda preferita, fatevi comodi e tuffiamoci dentro!

JavaScript - Closures

Cos'è una Chiusura?

Immaginate di avere una scatola magica che ricorda tutto ciò che c'è dentro, anche dopo averla chiusa. Questo è essenzialmente ciò che è una chiusura in JavaScript!

Una chiusura è una funzione che ha accesso alle variabili del suo ambito esterno (circostante) lessicale, anche dopo che la funzione esterna ha terminato l'esecuzione. È come se la funzione portasse intorno a sé un piccolo zaino di variabili che può usare quando ne ha bisogno.

Guardiamo un esempio semplice:

function funzioneEsterna(x) {
let y = 10;
function funzioneInterna() {
console.log(x + y);
}
return funzioneInterna;
}

let chiusura = funzioneEsterna(5);
chiusura(); // Output: 15

In questo esempio, funzioneInterna è una chiusura. "Ricorda" i valori di x e y anche dopo che funzioneEsterna ha terminato l'esecuzione.

Scoping Lessicale

Prima di addentrarci più a fondo nelle chiusure, dobbiamo capire lo scoping lessicale. È un termine complicato che semplicemente significa che una funzione può accedere alle variabili del suo ambito esterno.

let nome = "Alice";

function saluta() {
console.log("Ciao, " + nome + "!");
}

saluta(); // Output: Ciao, Alice!

Qui, saluta può accedere alla variabile nome grazie allo scoping lessicale. È come se saluta potesse vedere tutto nell'ambiente circostante.

Funzione Annidata

Le chiusure spesso implicano funzioni annidate. Guardiamo un esempio:

function esterna() {
let count = 0;
function interna() {
count++;
console.log(count);
}
return interna;
}

let contatore = esterna();
contatore(); // Output: 1
contatore(); // Output: 2

Qui, interna è annidata dentro esterna. La magia avviene perché interna ricorda la variabile count dal suo ambito esterno, anche dopo che esterna ha terminato l'esecuzione.

Funzione di Ritorno

Una delle cose affascinanti di JavaScript è che le funzioni possono restituire altre funzioni. Questo è un aspetto chiave delle chiusure.

function moltiplicatore(x) {
return function(y) {
return x * y;
};
}

let raddoppio = moltiplicatore(2);
console.log(raddoppio(5)); // Output: 10
console.log(raddoppio(3)); // Output: 6

In questo esempio, moltiplicatore restituisce una funzione che ricorda il valore di x. Questa funzione restituita è una chiusura.

Un Dilemma del Contatore

Guardiamo un problema comune che le chiusure possono risolvere:

function creaContatore() {
let count = 0;
return {
incrementa: function() {
count++;
},
getCount: function() {
return count;
}
};
}

let contatore = creaContatore();
contatore.incrementa();
contatore.incrementa();
console.log(contatore.getCount()); // Output: 2

Qui, la chiusura ci permette di avere variabili private (count) che possono essere accessibili solo attraverso i metodi forniti.

Esempio: Chiusure in JavaScript

Immergiamoci in un esempio più complesso per consolidare la nostra comprensione:

function creaSommatore(x) {
return function(y) {
return x + y;
};
}

let somma5 = creaSommatore(5);
let somma10 = creaSommatore(10);

console.log(somma5(2));  // Output: 7
console.log(somma10(2)); // Output: 12

In questo esempio, creaSommatore crea una chiusura che "ricorda" il valore di x. Possiamo creare più funzioni sommatore con valori preimpostati diversi.

Esempio

Ecco un altro esempio pratico di chiusure:

function creaSalutatore(saluto) {
return function(nome) {
console.log(saluto + ", " + nome + "!");
};
}

let salutaCiao = creaSalutatore("Ciao");
let salutaHi = creaSalutatore("Hi");

salutaCiao("Alice"); // Output: Ciao, Alice!
salutaHi("Bob");      // Output: Hi, Bob!

Questo esempio mostra come le chiusure possono essere utilizzate per creare funzioni personalizzate.

Vantaggi delle Chiusure

Le chiusure offrono diversi vantaggi:

  1. Privacy dei dati
  2. Fabbriche di funzioni
  3. Mantenimento dello stato

Esaminiamo questi in una tabella:

Vantaggio Descrizione Esempio
Privacy dei dati Le chiusure possono creare variabili private function contatore() { let count = 0; return { incrementa: () => ++count, getValue: () => count }; }
Fabbriche di funzioni Creare funzioni con parametri preimpostati function moltiplica(x) { return (y) => x * y; }
Mantenimento dello stato Tenere traccia dei dati tra le chiamate alle funzioni function creaGioco() { let score = 0; return { aggiungiPunto: () => ++score, getScore: () => score }; }

E voilà, ragazzi! Abbiamo percorso il territorio delle chiusure, dai concetti di base a quelli più avanzati. Ricordate, come ogni abilità, padroneggiare le chiusure richiede pratica. Quindi, non scoraggiatevi se non ci arrivate subito - continuate a programmare, continuate a sperimentare, e presto userete il potere delle chiusure come un vero mago di JavaScript! ?‍♂️✨

Credits: Image by storyset