[Javascript] spiegazione della closure

  • Creatore Discussione Creatore Discussione figlio1
  • Data di inizio Data di inizio

figlio1

Nuovo Utente
13 Feb 2018
3
0
1
24
Salve ragazzi , sto studiando javascript e mi sono imbattuto in questo codice :
Codice:
var saluto = "Buongiorno";
var visualizzaSaluti;

function saluta(persone) {
    
    var nomeCognome;
    var saluti = [];
    
    for (var i in persone) {
        nomeCognome = persone.nome + " " + persone.cognome;
        
        saluti.push(function() {
            console.log(saluto + " " + nomeCognome);
        });
    }
    return saluti;
}

visualizzaSaluti = saluta([{nome: "Mario", cognome: "Rossi"},
                           {nome: "Marco", cognome: "Neri"}]);

for (var i in visualizzaSaluti) {
    visualizzaSaluti();
}
Non riesco a capire come mai viene restituito all'array saluti l'ultimo oggetto 2 volte , dove ho preso il codice dice che centra con la variabile nomeCognome la quale ha l'ultimo elemento dell'array persona....me lo spiegate? dovrebbe centrare col closure ma non l'ho capito
 
Ultima modifica di un moderatore:
Ciao @figlio1
Da regolamento del forum, come tutti noi sei tenuto ad usare il tag
code.gif
quando posti del codice, oppure la funzione codice dalla barra degli strumenti
box inserisci 2.png.JPG

Inoltre ti prego di leggere attentamente il regolamento generale del forum e quello di sezione dove posti
Grazie
Per questa volta te lo sistemo io ma mi raccomando per il futuro
 
Ciao, premetto che eseguendo quello script salta fuori questo errore in console:
Codice:
TypeError: visualizzaSaluti is not a function
che chiaramente è dovuto al fatto che nell'ultimo ciclo stai cercando di trattare quella variabile come una funzione, cosa che non è ma piuttosto si tratta di un array i cui elementi sono, loro, delle funzioni. Presumo quindi che ci manchi l'indice , per cui dovrebbe essere visualizzaSaluti(); così come per la variabile persone nel ciclo dentro la funzione saluta(), che dovrebbe essere persone.nome e persone.cognome.

Non riesco a capire come mai viene restituito all'array saluti l'ultimo oggetto 2 volte , dove ho preso il codice dice che centra con la variabile nomeCognome la quale ha l'ultimo elemento dell'array persona....me lo spiegate? dovrebbe centrare col closure ma non l'ho capito
Sì, si tratta di una conseguenza dovuta alla closure (vedi definizione di Chiusura).

Riporto qui una definizione presa da un altro sito in cui forse è spiegato in maniera più abbordabile:
Una “chiusura” (closure) è quello che una funzione è capace di ricordare del contesto (lexical scope) dalla quale proviene, anche se viene eseguita al di fuori di esso.
(Fonte: http://codingjam.it/di-non-sapere-javascript-scope-e-closures/)

Ti direi che non è così semplice da spiegare perché comunque si devono avere chiari anche altri concetti, primo fra tutti il concetto di scope. Chiaramente queste nozioni, relativamente all'esempio che hai riportato qui, sono spiegate anche nella guida in cui hai trovato l'esempio stesso (che presumo tu abbia letto), per cui posso giusto darti un ulteriore commento con parole diverse ma sta poi a te sforzarti di capire.

In sostanza tu hai la funzione principale saluta() al cui interno stai definendo un array saluti e i suoi elementi, i quali non sono altro che delle funzioni (che poi andrai a richiamare dall'esterno della funzione principale:
Gli elementi sono quindi definiti in questo modo:
Codice:
saluti.push(function() {
    console.log(saluto + " " + nomeCognome);
});
Al loro interno (cioè dentro quel function(){}) stai usando (in particolare) la variabile nomeCognome che non è definita localmente dentro questa stessa function, ma è invece definita e valorizzata dentro il contesto (scope) della funzione principale saluta().

Cosa succede quindi? Tu hai lanciato una prima volta saluta() per valorizzare l'array visualizzaSaluti (che conterrà gli elementi/funzioni):
Codice:
visualizzaSaluti = saluta([{nome: "Mario", cognome: "Rossi"},
                           {nome: "Marco", cognome: "Neri"}]);

Successivamente stai richiamando queste funzioni in questo modo (chiaramente aggiungo l'indice mancante):
Codice:
for (var i in visualizzaSaluti) {
    visualizzaSaluti[i]();
}
Sarà quindi eseguita questa funzione (più volte, nel tuo caso 2, in base al numero di elementi definiti):
Codice:
function() {
    console.log(saluto + " " + nomeCognome);
}
dove la variabile nomeCognome era stata definita nello scope della funzione principale e ovviamente il suo valore non è altro che l'ultimo valore che gli è stato attribuito dopo che è stato eseguito il ciclo for (quello dentro la funzione principale).

Quindi, dal momento che tu stai richiamando, dall'esterno della funzione saluta(), queste altre funzioni che erano definite al suo interno, viene "ricordato" il valore delle variabili relativamente al contesto della stessa funzione saluta(); quindi il valore di nomeCognome è esattamente quello che gli è restato assegnato per ultimo dopo l'esecuzione del ciclo (dentro la funzione) e al termine dell'esecuzione della stessa funzione saluta().

Come è spiegato su quella guida, una soluzione a questo problema è l'uso di una IIFE , cioè una funzione che si auto-esegue, così da potergli passare come parametro il valore della variabile nomeCognome, in modo da restare "memorizzato" nello scope di quest'ultima funzione e non di quella principale.

Spero di aver chiarito qualcosa.
Buon proseguimento nello studio.
 

Discussioni simili