L'expression lambda de C # a également des fermetures mais est rarement discutée par les communautés ou les livres C #. Je vois beaucoup plus de personnes et de livres JavaScript parler de ses fermetures que dans le monde C #. Pourquoi donc?
L'expression lambda de C # a également des fermetures mais est rarement discutée par les communautés ou les livres C #. Je vois beaucoup plus de personnes et de livres JavaScript parler de ses fermetures que dans le monde C #. Pourquoi donc?
Réponses:
Parce que javascript n'a pas de fonctionnalités comme les espaces de noms, et vous pouvez gâcher assez facilement avec toutes sortes d'objets globaux.
Il est donc important de pouvoir isoler du code dans son propre environnement d'exécution. La fermeture est parfaite pour cela.
Cette utilisation de la fermeture n'a pas de sens dans un langage comme C # où vous avez des espaces de noms, des classes, etc. pour isoler le code et ne pas tout mettre dans la portée globale.
Une pratique très courante pour le code javascript est de l'écrire comme ceci:
(function(){
// Some code
})();
Comme vous pouvez le voir, il s'agit d'une déclaration de fonction anonyme, suivie immédiatement de son exécution. Ainsi, tout ce qui est défini dans la fonction est impossible d'accéder de l'extérieur et vous ne gâcherez pas la portée globale. Le contexte d'exécution de cette fonction restera actif tant que du code l'utilisera, comme les fonctions imbriquées définies dans ce contexte, que vous pouvez passer comme rappel ou autre.
Javascript est un langage très différent de C #. Ce n'est pas orienté objet, c'est orienté prototype. Cela conduit finalement à des pratiques très différentes.
Quoi qu'il en soit, les fermetures sont bonnes, alors utilisez-les, même en C #!
EDIT: Après quelques discussions sur le chat de stackoverflow, je pense que cette réponse doit être précisée.
La fonction dans l'exemple de code n'est pas une fermeture. Cependant, cette fonction peut définir une variable locale et des fonctions imbriquées. Toutes les fonctions imbriquées qui utilisent ces variables locales sont des fermetures.
Ceci est utile pour partager certaines données sur un ensemble de fonctions sans perturber la portée globale. Il s'agit de l'utilisation la plus courante de la fermeture en javascript.
La fermeture est beaucoup plus puissante que le simple partage de données comme celle-ci, mais soyons réalistes, la plupart des programmeurs ne connaissent rien à la programmation fonctionnelle. En C #, vous auriez utilisé une classe ou un espace de noms pour ce type d'utilisation, mais JS ne fournit pas cette fonctionnalité.
Vous pouvez faire bien plus avec la fermeture que simplement protéger la portée globale, mais c'est ce que vous verrez dans le code source JS.
Probablement parce que les implémentations populaires de l'orientation des objets JavaScript dépendent des fermetures. Regardons un exemple simple:
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());
Les méthodes getValue
et increase
sont en fait des fermetures, encapsulant la variable value
.
Parce que la plupart des bibliothèques qui rendent JavaScript «supportable» les utilisent.
Jetez un oeil à JQuery , Prototype ou MooTools , pour n'en nommer que trois populaires. Chacune de ces bibliothèques fournit une each
méthode pour leurs collections comme moyen d'itération préféré, qui utilise une fonction d'itérateur. Cette fonction, lors de l'accès aux valeurs dans la portée externe, sera une fermeture:
[1,2,3].each(function(item) {
console.log(item);
});
Et cela ne s'arrête pas là: les rappels dans Ajax, la gestion des événements dans Ext.js, etc. prennent toutes des fonctions, et si vous ne voulez pas gonfler votre code avec 100eds de fonctions qui sont appelées une seule fois, les fermetures sont le chemin à parcourir.
console.log
est défini dans une portée externe, tout console
comme une «variable libre». Et pourquoi, en effet, une boucle for, qui ne fait rien de différent, est-elle une mauvaise pratique?
Je suis d'accord avec les autres réponses selon lesquelles un "bon" codage avec JavaScript dépend davantage des fermetures. Cependant, en plus de cela, il s'agit probablement simplement de la durée de la fonctionnalité dans chaque langue. JavaScript a essentiellement été fermé depuis ses premières implémentations. C # d'autre part ne les a que depuis la version 3.0, qui a été publiée avec Visual Studio 2008.
Beaucoup de programmeurs C # que je rencontre travaillent toujours sur des projets 2.0. Et même s'ils fonctionnent en 3.0 ou 4.0, ils utilisent souvent toujours des idiomes 2.0. J'aime les fermetures; nous espérons qu'ils deviendront plus largement utilisés en C # à mesure que le concept se propage parmi les développeurs C #.
La raison principale est que C # est typé statiquement et que les fonctions n'ont accès qu'à un seul environnement prédéterminé, ce qui empêche l'utilité des fermetures.
En JavaScript, en revanche, les fermetures permettent aux fonctions de se comporter comme des méthodes lorsqu'elles sont accédées en tant que propriété d'objet et étant des objets de première classe, elles peuvent également être injectées dans différents environnements, ce qui permet aux sous-programmes de fonctionner dans différents contextes.
Une des raisons pour lesquelles j'ai dû en apprendre davantage était que lorsque vous parcourez des éléments DOM (ou quoi que ce soit vraiment), vous voulez pouvoir "fermer" ou "encapsuler" la portée de la variable. Comme dans l'exemple publié ici: /programming/5606059/how-to-create-closure-in-loop-and-store-it-in-variable-for-later-execution