Pourquoi la fermeture est-elle importante pour JavaScript?

16

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?

TomCaps
la source
3
Parce que JavaScript est traité comme un langage fonctionnel de première classe et C # est un langage OOP classique. Différents paradigmes, différents styles de programmation.
Raynos
1
Avoir une fonction de première classe fait du langage un langage fonctionnel. PHP (depuis 5.3), python ou D a une fonction de première classe. Diriez-vous que ce sont des langages fonctionnels? Certainement pas, et javascript non plus.
deadalnix
1
@deadalnix JavaScript est un langage multi-paradigme. Il prend principalement en charge le paradigme OO procédural, fonctionnel et prototypique. Ce n'est en aucun cas un langage fonctionnel pur , mais vous pouvez facilement écrire du javascript dans le paradigme fonctionnel sans plier le langage. Je dirais la même chose de C # et de python.
Raynos
3
@deadalnix, un langage qui permet de définir un combinateur Y est un langage fonctionnel. Par définition.
SK-logic
1
@deadalnix: Je suppose que cela se résume à la question de savoir quelles approches sont promues par le langage. Il existe de nombreux frameworks et plates-formes JavaScript (notamment node.js et DOM (modèle d'événement)) qui dépendent fortement des fonctions de premier ordre. PHP a les fonctionnalités qui permettent le même style de programmation, mais si vous jetez un œil à l'API standard ou à de nombreux frameworks, vous voyez que ce n'est pas vraiment au cœur du langage.
back2dos

Réponses:

5

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.

deadalnix
la source
9
Ce n'est pas une fermeture. Vous décrivez l'avantage d'utiliser des fonctions pour créer une portée locale.
Raynos
2
une fermeture n'est une fermeture que si elle se ferme sur des variables libres. Merci aussi de me dire que je ne sais pas comment JavaScript fonctionne :)
Raynos
2
au lieu de recourir à me miner en m'appelant un débutant, n'hésitez pas à présenter des arguments réels dans la salle de discussion JavaScript SO . Cette discussion n'a pas vraiment sa place ici, mais je discuterai avec plaisir de vos idées fausses dans le chat SO.
Raynos
1
Voté. JavaScript est largement orienté objet. Ce n'est tout simplement pas basé sur une classe, mais une telle fonctionnalité est facilement créée. Il a des fonctions de première classe, profite des fermetures pour en faire un choix naturel pour les paradigmes fortement axés sur les événements, et une source principale d'inspiration selon son auteur, Brendan Eich, était Scheme. Je ne suis pas vraiment sûr de ce que vous pensez d'un langage fonctionnel, mais la partie amusante est que vous semblez penser que l'héritage basé sur les classes est en quelque sorte critique plutôt que plus nécessaire lorsque vous pouvez passer des fonctions et les appliquer dans de nouveaux contextes.
Erik Reppen
2
-1 aussi. Cela ne décrit pas les fermetures, il décrit la portée.
Izkata
12

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 getValueet increasesont en fait des fermetures, encapsulant la variable value.

user281377
la source
3
-1 "dépend des fermetures" C'est très subjectif. Ce ne est pas.
Raynos
Raynos: vous voulez nous montrer comment créer et utiliser des membres privés sans fermetures?
user281377
1
@ammoQ, il n'y a rien de privé en JavaScript. Ce que vous vouliez dire était "parce que l'émulation OO JavaScript classique dépend des fermetures". JavaScript OO est un prototype qui est un paradigme différent. C'est une bonne réponse à la question, "Nous utilisons des fermetures en JavaScript car il fallait émuler des OO classiques"
Raynos
1
@keppla Je voulais dire que "OO dépend des fermetures" est subjectif. Vous n'avez pas du tout besoin de fermetures pour OO.
Raynos
2
vous
m'exposez
4

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 eachmé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.

keppla
la source
1
Pourquoi n'est-ce pas une fermeture? console.logest défini dans une portée externe, tout consolecomme une «variable libre». Et pourquoi, en effet, une boucle for, qui ne fait rien de différent, est-elle une mauvaise pratique?
keppla
@Raynos: ma définition de la fermeture est «bloc qui contient une variable libre», il ne perd pas ce statut, il se trouve que la variable libre est sur la portée supérieure. Mais, pour soutenir mon point, considérez cette méthode: pastie.org/2144689 . Pourquoi cela devrait-il être mauvais?
keppla
Je pense toujours que la «fermeture» des données mondiales est considérée comme une fraude. Je suis d'accord que l'accès aux données dans la chaîne de portée est très bien, c'est simplement une bonne pratique pour minimiser cet accès.
Raynos
Convenu de minimiser l'accès
keppla
Il convient de noter qu'avec les itérateurs de tableau (pour chacun, mapper, réduire, etc.), il n'y a aucune raison pour qu'ils soient des fermetures, ils ont tous l'état directement transmis. Je considérerais cela comme un motif anti-fermeture pour eux
Raynos
3

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 #.

RationalGeek
la source
2

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.

Filip Dupanović
la source
1
Qu'est-ce que la saisie statique a à voir avec cela? Les fermetures sont orthogonales.