Quel est l'avantage d'une fonction sans paramètres qui n'appelle qu'une autre fonction


21

Un tutoriel (pour Javascript) que je fais suggère d'écrire une fonction comme celle-ci:

function sayHello() {
   //Some comments explaining the next line
   window.alert("Hello");
}

À part l'obscurcissement, y a-t-il des avantages à écrire quelque chose comme ça dans la vraie vie? Si oui, quels en sont les avantages?


14
Il s'agit probablement simplement de vous montrer comment définir vos propres fonctions.
Doval

4
Je n'écrirais jamais de code de telle manière à l'obscurcir - le code est pour le programmeur de lire facilement, pas l'inverse. Utilisez un obscurcisseur pour l'obscurcissement.
rhughes

32
L'avantage est qu'il encapsule une fonction avec des paramètres. De cette façon, si vous souhaitez par la suite rendre votre application espagnole, il vous suffit de remplacer "Bonjour" par "Ola" en un seul endroit.
Pieter B

9
@PieterB en fait, "Hola"
rev

29
@PieterB - Et si vous découvrez que vous avez mal orthographié "Hola", vous n'avez qu'à le réparer au même endroit.
Daniel R Hicks

Réponses:


60

Veuillez pardonner ma mémoire si j'ai ce mauvais ... Javascript n'est pas ma langue d'implémentation préférée.

Il y a plusieurs raisons pour lesquelles une fonction no arg devrait envelopper un autre appel de fonction. Alors que le simple appel à window.alert("Hello");est quelque chose que vous pourriez imaginer au lieu d'appeler directement à la place sayHello().

Mais que se passe-t-il s'il y a plus? Vous avez une douzaine d'endroits où vous souhaitez appeler sayHello()et avez écrit à la window.alert("Hello");place. Maintenant, vous voulez qu'il fasse window.alert("Hello, it is now " + new Date()). Si vous avez encapsulé tous ces appels lorsque sayHello()vous le changez d'un seul endroit. Sinon, vous le changez dans une douzaine d'endroits. Cela touche à ne pas vous répéter . Vous le faites parce que vous ne voulez pas avoir à le faire une douzaine de fois à l'avenir.

J'ai travaillé avec une bibliothèque i18n / l10n dans le passé qui utilisait des fonctions pour effectuer la localisation côté client du texte. Considérez la sayHello()fonction. Vous pouvez le faire imprimer holalorsque l'utilisateur est localisé dans une langue espagnole. Cela pourrait ressembler à quelque chose comme:

function sayHello() {
  var language = window.navigator.userLanguage || window.navigator.language;
  if(language === 'es') { window.alert('Hola'); }
   else { window.alert("Hello"); }
}

Cependant, ce n'est pas ainsi que la bibliothèque a fonctionné. Au lieu de cela, il avait un ensemble de fichiers qui ressemblait à:

# English file
greeting = hello
# Spanish file
greeting = hola

Et puis la bibliothèque détecterait le paramètre de langue du navigateur, puis créerait des fonctions dynamiques avec la localisation appropriée comme valeur de retour pour un appel de fonction sans argument basé sur le fichier de localisation approprié.

Je ne suis pas assez d'un codeur Javascript pour dire si c'est bon ou mauvais ... juste que c'était et peut être vu comme une approche possible.

Le fait est que l'encapsulation de l'appel à une autre fonction dans une fonction propre est souvent très utile et aide à la modularisation de l'application et peut également entraîner une lecture plus facile du code.

À part cela, vous travaillez à partir d'un didacticiel. Il faut introduire les choses le plus simplement possible au départ. L'introduction d'appels de fonction de style varargs dès le début peut entraîner un code très déroutant pour une personne qui n'est pas familière avec le codage en général. Il est beaucoup plus facile de passer d’aucun argument, à des arguments, à un style varargs - avec chaque construction sur les exemples et la compréhension précédents.


3
window.alertest également souvent utilisé comme espace réservé pendant le développement jusqu'à ce qu'un joli modal / popup puisse être conçu / implémenté, donc, tout comme le problème de langue, il peut être désactivé beaucoup plus facilement. Ou si vous en avez déjà un, une mise à jour de la conception dans quelques années pourrait nécessiter des modifications similaires.
Izkata

34

Je pense que son utile parfois pour cacher la mise en œuvre.

 function sayHello() {
  window.alert("Hello");
 }

Et cela vous donne la flexibilité de le changer plus tard

 function sayHello() {
  console.log("Hello");
 }

19

À part l'obscurcissement, y a-t-il des avantages à écrire quelque chose comme ça dans la vraie vie? Si oui, quels en sont les avantages?

  • centralisation: bien que l'implémentation soit longue d'une seule ligne, si c'est une ligne qui change souvent, vous préférez probablement la changer en un seul endroit, que partout où sayHello est appelé.

  • minimisation / masquage des dépendances: votre code client n'a plus besoin de savoir qu'il y a un objet fenêtre, et vous pouvez même modifier l'ensemble de l'implémentation sans affecter le code client du tout

  • exécution du contrat: le code client peut s'attendre à un module doté d'une fonction sayHello. Dans ce cas, même si c'est trivial, alors la fonction doit être là.

  • consistance des niveaux d'abstraction: si le code client utilise des opérations de haut niveau, il est dans votre intérêt d'écrire du code client en termes de `` sayHello, sayBye '' et d'autres fonctions `` sayXXX '', au lieu d'objets de fenêtre. En fait, dans le code client, vous ne voudrez peut-être même pas savoir qu'il existe un objet "fenêtre".


J'aime cette réponse. Souvent, la conception est la raison principale de ces fonctions, en particulier la conception OO où vous voulez que les objets responsables du comportement exécutent les fonctions d'autres objets avec un comportement spécifique. Imager votre voiture, plus particulièrement vos changements de vitesse. Vous passez votre vitesse en "disant" à votre bâton de passer la vitesse supérieure. À son tour, il transmet cet appel à votre boîte de vitesses. Mais en plus, il vérifie d'abord que vous pouvez passer de votre position actuelle.
Eric

3
Les autres raisons sont bonnes mais +1 pour mentionner les niveaux d'abstraction. L'utilisation d'abstractions claires et de bons noms de fonction peut faciliter la lecture et la maintenance de l'ancien code. Au moment où sayHello () est appelé, vous n'êtes pas nécessairement concerné par la façon dont il est implémenté, vous voulez juste comprendre quelle est l'intention de cette ligne de code. Et un nom de fonction comme sayHello () rend cela évident.
kkrambo

+1 également pour mentionner les niveaux d'abstraction: il peut arriver que l'implémentation d'une fonction à un niveau d'abstraction consiste en un appel à une autre fonction d'un niveau d'abstraction inférieur. Et alors?
Giorgio

7

Étonnant que pas une seule autre personne n'ait mentionné les tests.

La ligne "enveloppée" particulière que vous avez choisie, window.alert('hello')en est un parfait exemple. Tout ce qui concerne l' windowobjet est vraiment, vraiment douloureux à tester. Multipliez cela par 1000 fois dans votre application et je garantis que les développeurs abandonneront éventuellement les tests. D'un autre côté, il est assez facile de simplement assommer la sayHellofonction avec un espion et de tester qu'elle a été appelée.

Un exemple plus pratique - car vraiment, qui utilise réellement window.alert(...)dans le code de production? - vérifie l'horloge système. Ainsi, par exemple, ce serait envelopper DateTime.Nowdans .NET, time(...)en C / C ++, ouSystem.currentTimeMillis() en Java. Vous voulez vraiment envelopper ceux-ci dans une dépendance que vous pouvez injecter, car ils sont non seulement (presque) impossibles à simuler / faux, ils sont en lecture seule et non déterministes . Tout test couvrant une fonction ou une méthode qui utilise directement la fonction d'horloge système est extrêmement susceptible de souffrir de pannes intermittentes et / ou aléatoires.

L'emballage réel est une fonction sur une ligne - return DateTime.Now- mais c'est tout ce dont vous avez besoin pour prendre un objet mal conçu et non testable et en faire un objet propre et testable. Vous pouvez remplacer une fausse horloge par le wrapper et régler son heure à votre guise. Problème résolu.


2

Comme l'a dit Doval, cet exemple essaie probablement de vous présenter les fonctions. Je suis général, cependant, c'est utile. Surtout en spécifiant certains mais pas tous les arguments, et en passant les autres, vous pouvez créer une fonction plus spécifique à la casse à partir d'une fonction plus générale. À titre d'exemple quelque peu banal, considérons une fonction de tri qui prend un tableau pour trier et une fonction de comparateur pour trier avec. En spécifiant une fonction de comparateur qui compare par valeur numérique, je peux créer une fonction sortByNumericalValue et les appels à cette fonction sont beaucoup plus clairs et concis.


2

La pensée derrière votre question semble être: "Pourquoi ne pas simplement écrire alert("Hello"); directement? C'est assez simple."

La réponse est, en partie, parce que vous ne voulez pas vraiment appeler alert("Hello")- vous voulez juste dire bonjour.

Ou: Pourquoi stocker des contacts sur votre téléphone, alors que vous pouvez simplement composer des numéros de téléphone? Parce que vous ne voulez pas vous souvenir de tous ces chiffres; parce que composer des numéros est fastidieux et sujet aux erreurs; parce que le nombre peut changer, mais c'est toujours la même personne à l'autre bout. Parce que tu veux appeler gens , pas des numéros.

C'est ce que l'on entend par des termes comme abstraction, indirection, «masquage des détails d'implémentation» et même «code expressif».

Le même raisonnement s'applique à l'utilisation de constantes au lieu d'écrire des valeurs brutes partout. Tu pourrais simplement écrire à 3.141592...chaque fois que vous avez besoin de π, mais heureusement, il y aMath.PI .

On pourrait aussi regarder alert() . Qui se soucie de la façon dont il construit et affiche cette boîte de dialogue d'alerte? Vous voulez simplement alerter l'utilisateur. Entre l'écriture alert("Hello")et le changement des pixels de votre écran, il y a une pile profonde et profonde de code et de matériel, chaque couche indiquant à la suivante ce qu'elle veut, et cette couche suivante s'occupe des détails jusqu'à ce que la couche la plus profonde possible retourne quelques bits dans le Mémoire vidéo.

Vous ne voulez vraiment pas avoir à faire tout cela vous-même juste pour dire bonjour.

La programmation - enfin, n'importe quelle tâche, en réalité - consiste à diviser des problèmes complexes en morceaux gérables. La résolution de chaque bloc vous donne un bloc de construction, et avec suffisamment de blocs de construction simples, vous pouvez construire de grandes choses.

C'est l'algèbre.


-1

C'est une bonne idée de garder le calcul des valeurs (expressions) séparé de l' exécution des actions (déclarations). Nous voulons un contrôle précis sur où et quand les actions seront prises (comme afficher des messages), mais lors du calcul des valeurs, nous préférons travailler à un niveau plus abstrait et ne pas avoir à nous soucier de la façon dont ces valeurs sont calculées.

Une fonction qui calcule uniquement une valeur de retour, en utilisant uniquement les arguments qui lui sont donnés, est appelée pure .

Une "fonction" qui exécute une action est en fait une procédure qui a un effet .

Tous les effets provoqués lors du calcul d'une valeur sont appelés effets secondaires , et il vaut mieux les éviter dans la mesure du possible ("J'avais juste besoin de cette chaîne, je ne savais pas qu'elle martellerait la base de données!").

Pour minimiser le risque d'effets secondaires, nous devons éviter d'envoyer trop de données à nos procédures ou d'y mettre des calculs; si un calcul doit être effectué au préalable, il est généralement préférable de le faire séparément dans une fonction pure, puis de ne transmettre que le résultat requis à la procédure. Cela permet de garder le but de la procédure clair et de réduire les chances qu'elle soit réutilisée ultérieurement dans le cadre d'un calcul (la fonction pure peut être réutilisée à la place).

Pour la même raison, nous devons éviter de traiter les résultats dans une procédure. Il est préférable de renvoyer le résultat (le cas échéant) de notre action et d'effectuer tout traitement ultérieur avec des fonctions pures.

Si nous suivons ces règles, nous pourrions nous retrouver avec une procédure comme sayHello , qui n'a pas besoin de données et n'a pas de résultat. Par conséquent, la meilleure interface pour cela est de n'avoir aucun argument et de ne pas renvoyer de valeur. C'est préférable, par exemple, d'appeler "console.log" au milieu d'un calcul.

Pour réduire le besoin d'effets pendant le calcul, nous pouvons avoir des calculs qui renvoient des procédures ; par exemple. si nous devons décider d'une action à entreprendre, nous pouvons demander à une fonction pure de choisir une procédure et de la renvoyer, plutôt que de l'exécuter directement.

De même, pour réduire le besoin de calcul lors des procédures, nous pouvons demander aux procédures de prendre d'autres procédures comme paramètres (éventuellement le résultat d'une fonction); par exemple. prendre un tableau de procédures et les exécuter les unes après les autres.


Vous semblez plaider contre la POO ici, où le principe fondamental est «dites, ne demandez pas». Suivre les conseils ici est ce qui mène normalement au code criblé d'appels inutiles "getFoo", "setFoo" et "execute". La POO consiste à combiner des données et des comportements, pas à les séparer.
Aaronaught

@Aaronaught C'est vrai que je suis contre la POO, mais je ne recommanderais certainement pas d' setFooappels, car cela implique des données mutables. La modification du contenu des variables / propriétés est un effet qui rend impurs tous les calculs utilisant ces données. Je ne recommanderais pas les executeappels en tant que tels, mais je voudrais recommander des runFooprocédures pour l' exécution d' actions en fonction de leurs arguments.
Warbo

-2

Je dirais que c'est une combinaison des réponses données par @MichaelT et @Sleiman Jneidi.

Il y a peut-être un certain nombre d'endroits dans le code où vous souhaitez saluer l'utilisateur avec un message Hello afin que vous emballiez cette idée dans une méthode. Dans la méthode, vous pouvez le traduire ou développer un simple «Bonjour» en affichant un texte plus long. Vous pouvez également utiliser une belle boîte de dialogue JQuery à la place d'une alerte.

Le fait est que la mise en œuvre est en un seul endroit. Vous avez juste besoin de changer le code en un seul endroit. (SayHello () est peut-être un exemple trop simple)


@downvoter (s) - prenez soin de partager vos connaissances avec le reste d'entre nous. Mon message est-il simplement faux, mal écrit ou quoi?
Paul
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.