Anche l'espressione lambda di C # ha delle chiusure ma è raramente discussa dalle comunità o dai libri di C #. Vedo che molte più persone e libri JavaScript parlano delle sue chiusure di quanto non facciano nel mondo C #. Perché?
Anche l'espressione lambda di C # ha delle chiusure ma è raramente discussa dalle comunità o dai libri di C #. Vedo che molte più persone e libri JavaScript parlano delle sue chiusure di quanto non facciano nel mondo C #. Perché?
Risposte:
Perché JavaScript non ha funzionalità come gli spazi dei nomi e puoi fare confusione abbastanza facilmente con tutti i tipi di oggetti globali.
Quindi è importante essere in grado di isolare un po 'di codice nel proprio ambiente di esecuzione. La chiusura è perfetta per questo.
Questo uso della chiusura non ha senso in un linguaggio come C # in cui si hanno spazi dei nomi, classi e così via per isolare il codice e non mettere tutto nell'ambito globale.
Una pratica molto comune per il codice javascript è scrivere in questo modo:
(function(){
// Some code
})();
Come puoi vedere, questa è una dichiarazione di funzione anonima, seguita immediatamente dalla sua esecuzione. Pertanto, è impossibile accedere a qualsiasi cosa definita all'interno della funzione dall'esterno e non confonderai l'ambito globale. Il contesto di esecuzione di questa funzione rimarrà in vita finché un codice lo utilizza, come le funzioni nidificate definite in questo contesto, che è possibile passare come callback o altro.
Javascript è un linguaggio molto diverso da C #. Non è orientato agli oggetti, è orientato ai prototipi. Questo porta a pratiche molto diverse alla fine.
Comunque, le chiusure sono buone, quindi usale, anche in C #!
EDIT: Dopo alcuni discorsi sulla chat di StackOverflow, penso che questa risposta debba essere precisa.
La funzione nel codice di esempio non è una chiusura. Tuttavia, questa fucntion può definire variabili locali e funzioni nidificate. Tutte le funzioni nidificate che utilizzano queste variabili locali sono chiusure.
Questo è utile per condividere alcuni dati tra una serie di funzioni senza incasinare l'ambito globale. Questo è l'uso più comune di chiusura in javascript.
La chiusura è molto più potente della semplice condivisione di alcuni dati come questo, ma siamo realistici, la maggior parte dei programmatori non sa nulla della programmazione funzionale. In C # avresti usato la classe o uno spazio dei nomi per questo tipo di utilizzo, ma JS non fornisce questa funzionalità.
Con la chiusura puoi fare molto di più che proteggere l'ambito globale, ma questo è ciò che vedrai nel codice sorgente di JS.
Probabilmente perché le implementazioni popolari dell'orientamento agli oggetti JavaScript dipendono dalle chiusure. Diamo un'occhiata a un semplice esempio:
function counter() {
var value = 0;
this.getValue = function() { return value; }
this.increase = function() { value++; }
}
var myCounter = new counter();
console.log(myCounter.getValue());
myCounter.increase();
console.log(myCounter.getValue());
I metodi getValue
e increase
sono infatti chiusure, incapsulando la variabile value
.
Perché molte delle librerie che rendono JavaScript "sopportabile" le usano.
Dai un'occhiata a JQuery , Prototype o MooTools , solo per citarne tre popolari. Ognuna di queste librerie fornisce un each
metodo per le proprie raccolte come modo preferito di iterazione, che utilizza una funzione iteratore. Tale funzione, quando si accede ai valori nell'ambito esterno, sarà una chiusura:
[1,2,3].each(function(item) {
console.log(item);
});
E non si ferma qui: i callback in Ajax, la gestione degli eventi in Ext.js, ecc. Prendono tutte le funzioni, e se non vuoi gonfiare il tuo codice con 100eds di funzioni che vengono chiamate esattamente una volta, le chiusure sono la strada da percorrere.
console.log
è definito in un ambito esterno, quindi console
è una "variabile libera". E perché, in effetti, è un for-loop, che non fa nulla di diverso, una cattiva pratica?
Concordo con le altre risposte che la "buona" codifica con JavaScript dipende maggiormente dalle chiusure. Tuttavia, oltre a ciò, è probabilmente solo una questione di quanto tempo la funzionalità è in circolazione in ogni lingua. JavaScript ha praticamente chiuso chiusure sin dalle sue prime implementazioni. D'altra parte C # li ha solo dalla 3.0, che è stato rilasciato con Visual Studio 2008.
Molti programmatori C # in cui mi imbatto stanno ancora lavorando su progetti 2.0. E anche se funzionano in 3.0 o 4.0, spesso usano ancora i modi di dire 2.0. Adoro le chiusure; speriamo che vengano usati più pesantemente in C # mentre il concetto si propaga tra gli sviluppatori di C #.
Il motivo principale è perché C # è tipizzato staticamente e le funzioni hanno accesso solo a un unico ambiente predeterminato, che impedisce l'utilità delle chiusure.
In JavaScript, d'altra parte, le chiusure consentono alle funzioni di comportarsi come metodi quando si accede come proprietà di un oggetto ed essendo oggetti di prima classe, possono anche essere iniettate in diversi ambienti che consentono alle subroutine di operare in contesti diversi.
Uno dei motivi per cui ho dovuto conoscerli è stato il fatto che quando si esegue il ciclo tra gli elementi DOM (o qualsiasi cosa realmente), si desidera poter "chiudere" o "incapsulare" l'ambito variabile. Come nell'esempio pubblicato qui: /programming/5606059/how-to-create-closure-in-loop-and-store-it-in-variable-for-later-execution