Pourquoi le passage de grandes fonctions anonymes comme arguments à d'autres fonctions est-il si largement accepté en JavaScript?

27

J'ai une opinion (qui, j'en suis sûr, sera partagée par certains) selon laquelle le fait de passer des fonctions anonymes qui contiennent plus de quelques lignes de code, car les arguments d'autres fonctions affectent considérablement la lisibilité et l'auto-documentation, au point où je pense que cela être beaucoup mieux pour quiconque utilisera probablement le code pour simplement déclarer une fonction nommée. Ou au moins affecter cette fonction anonyme à une variable avant de déclarer la fonction principale

Cependant, de nombreuses bibliothèques JavaScript (jQuery, d3.js / NVD3.js), pour ne donner que quelques exemples, utilisent de grandes fonctions de cette manière.

Pourquoi est-ce si largement accepté en JavaScript? Est-ce une chose culturelle, ou y a-t-il des avantages qui me manquent, qui rendraient l'utilisation plus préférée que la déclaration d'une fonction nommée?

Adam Copley
la source
1
Cela a probablement beaucoup à voir avec l'utilisation des fermetures . Cela peut également avoir à voir avec le fait de ne pas vouloir exposer la fonction réelle au monde extérieur (c'est pourquoi elle est anonyme).
Robert Harvey
3
@RobertHarvey En d'autres termes, c'est une solution de contournement pour JavaScript n'ayant pas public et privé ?
Mason Wheeler
2
Dans de nombreux endroits, une grande fonction anonyme ressemble plus à un bloc et se sent généralement bien une fois que vous vous y êtes habitué. Les règles de portée prennent même en charge la sensation de bloc.
5
@MasonWheeler: Cela dépend de votre point de vue. Un programmeur Scheme ou ECMAScript pourrait dire cela publicet privatesont des solutions de contournement pour ne pas avoir de fermetures appropriées.
Jörg W Mittag
1
@ JörgWMittag Hooray for Racket, le sponsor officiel de la langue du XKCD 927!
Mason Wheeler

Réponses:

23

Trois raisons principales auxquelles je peux penser:

  1. Accès à l'étendue parent
  2. Intimité
  3. Réduction des noms définis dans les étendues supérieures

Accès à l'étendue parent: les définitions de fonction en ligne permettent au code en ligne d'avoir accès aux variables définies dans les étendues parent. Cela peut être très utile pour de nombreuses choses et peut réduire la quantité ou la complexité du code s'il est fait correctement.

Si vous placez le code dans une fonction définie en dehors de cette portée, puis appelez le code, vous devrez alors passer tout état parent auquel il souhaite accéder à la fonction.

Confidentialité: le code dans une définition anonyme en ligne est plus privé et ne peut pas être appelé par un autre code.

Réduction des noms définis dans les étendues supérieures: c'est le plus important lorsque vous travaillez dans la portée globale, mais une déclaration anonyme en ligne évite d'avoir à définir un nouveau symbole dans la portée actuelle. Étant donné que Javascript ne nécessite pas nativement l'utilisation d'espaces de noms, il est sage d'éviter de définir plus de symboles globaux que nécessaire.


Éditorial: Cela semble être devenu une chose culturelle en Javascript où déclarer quelque chose de manière anonyme en ligne est en quelque sorte considéré comme "mieux" que de définir une fonction et de l'appeler même lorsque l'accès à l'étendue parent n'est pas utilisé. Je soupçonne que c'était d'abord à cause du problème de pollution de l'espace de noms global dans Javascript, puis peut-être à cause de problèmes de confidentialité. Mais il est maintenant devenu quelque chose de quelque chose de culturel et vous pouvez le voir exprimé dans de nombreux organismes publics de code (comme ceux que vous mentionnez).

Dans des langages comme C ++, la plupart considéreraient probablement comme une pratique loin d'être idéale d'avoir une fonction géante qui s'étend sur plusieurs pages / écrans. Bien sûr, C ++ a un espace de noms intégré, ne fournit pas d'accès à l'étendue parent et a des fonctionnalités de confidentialité, il peut donc être entièrement motivé par la lisibilité / maintenabilité tandis que Javascript doit utiliser l'expression de code pour atteindre la confidentialité et l'accès à l'étendue parent. Ainsi, JS semble simplement avoir été motivé dans une direction différente et c'est devenu quelque chose de culturel dans la langue, même lorsque les éléments qui ont motivé cette direction ne sont pas nécessaires dans un cas spécifique.

jfriend00
la source
Comme un développeur C ++ a récemment migré vers JS pour une grande partie de mon travail, cette réponse a beaucoup de sens, en particulier le point d'accès à la portée parent - elle a vraiment le pouvoir de simplifier considérablement votre code. Un nitpick - C ++ fournit un accès de portée parent dans C ++ 11 lambdas :) Certainement +1 cependant.
Commandant Coriander Salamander
8

Les fonctions anonymes sont utilisées à bien plus de fins en JavaScript que dans la plupart des langues.

Tout d'abord, ils sont utilisés pour l'espace de noms et la portée des blocs. Jusqu'à récemment, JavaScript manquait de modules ou de tout autre type de mécanisme d'espacement de noms, ce qui a conduit à utiliser des fonctions anonymes pour fournir cette fonctionnalité via le modèle de module. Il n'y aurait absolument aucun avantage à nommer ces fonctions. À une échelle plus petite, en raison de l'absence de portée de bloc de JavaScript jusqu'à récemment, un modèle similaire a été utilisé pour imiter la portée de bloc; plus particulièrement dans le corps des boucles. L'utilisation d'une fonction nommée dans ce cas serait activement obscurcissante.

Deuxièmement, et moins spécifiques à JavaScript, les fonctions anonymes sont souvent utilisées avec des fonctions d'ordre supérieur qui imitent les structures de contrôle. Par exemple, la eachméthode de jQuery . Je doute que vous absteniez chaque corps de boucle ou si-branche dans une fonction chaque fois qu'elle fait plus de quelques lignes. La même logique s'applique dans ce cas.

Une dernière raison est que la programmation basée sur les événements est courante en JavaScript, ce qui a tendance à conduire à un code de style passant par inadvertance . Vous effectuez un appel AJAX et enregistrez un rappel qui, une fois exécuté, fera un autre appel AJAX et enregistrera un rappel, etc. Si les appels étaient synchrones plutôt qu'asynchrones, ce ne serait qu'une séquence de code en ligne droite dans une seule étendue lexicale . Encore une fois, je doute que vous résumiez toutes les quelques lignes de code linéaire dans une fonction.

Il existe également des facteurs culturels et, pour les raisons ci-dessus, entre autres, les fonctions anonymes sont beaucoup plus courantes dans JavaScript que dans de nombreuses autres langues et sont utilisées plus confortablement / avec laxisme que de nombreuses autres langues.

Derek Elkins
la source
Mes propres structures, peut-être naïves, dans le codage C ++ ont parfois pris des principes de codage basé sur des événements et des rappels de JavaScript via std :: function et lambdas. Dans mon cas, c'est en partie parce que je fais du code d'interface utilisateur en C ++ et que je ne veux pas effectuer d'opérations de blocage. Je suis curieux de savoir si les pratiques de JavaScript sont simplement utiles à n'importe qui tant que le langage les prend bien en charge.
Katana314