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?
language-agnostic
functions
Daniel
la source
la source
Réponses:
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 placesayHello()
.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 à lawindow.alert("Hello");
place. Maintenant, vous voulez qu'il fassewindow.alert("Hello, it is now " + new Date())
. Si vous avez encapsulé tous ces appels lorsquesayHello()
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 imprimerhola
lorsque l'utilisateur est localisé dans une langue espagnole. Cela pourrait ressembler à quelque chose comme:Cependant, ce n'est pas ainsi que la bibliothèque a fonctionné. Au lieu de cela, il avait un ensemble de fichiers qui ressemblait à:
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.
la source
window.alert
est é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.Je pense que son utile parfois pour cacher la mise en œuvre.
Et cela vous donne la flexibilité de le changer plus tard
la source
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".
la source
É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'window
objet 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 lasayHello
fonction 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 envelopperDateTime.Now
dans .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.la source
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.
la source
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'écriturealert("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.
la source
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.
la source
setFoo
appels, 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 lesexecute
appels en tant que tels, mais je voudrais recommander desrunFoo
procédures pour l' exécution d' actions en fonction de leurs arguments.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)
la source