Tutoriel pour apprendre la programmation en JavaScript


précédentsommairesuivant

IV. TP 4 : Fonctions

Objectifs :

  • Savoir développer le jeu ChiFouMi (pierre feuille ciseaux)
  • Création d'algorithmes à l'aide de boucles, et de fonctions

IV-A. Fonctions en JavaScript

IV-A-1. Introduction

Comme en mathématiques, une fonction transforme des paramètres (en « entrée ») en une valeur de résultat (la « sortie »), lorsqu'elle est appelée. Avant de pouvoir l'appeler, on la définit par une suite d'instructions qui déterminera cette valeur de résultat, en fonction des paramètres qui lui seront passés.

Image non disponible

Définir une fonction permet de regrouper des instructions JavaScript, afin qu'elles puissent être exécutées à différentes occasions, sans avoir à dupliquer le code correspondant.

Par exemple, sur le web, les fonctions JavaScript sont utilisées par le développeur pour définir le comportement que doit suivre le navigateur lorsque l'utilisateur effectue certaines actions (ex. : saisie dans un champ, clic sur un bouton, soumission d'un formulaire).

IV-A-2. Définition et appel de fonction

On définit une fonction de la manière suivante :

 
Sélectionnez
1.
2.
3.
4.
5.
function nomDeLaFonction (parametre1, parametre2, parametre3 ...) {
  // instructions javascript
  // pouvant utiliser les paramètres parametre1, parametre2 et parametre3
  return resultat;
}

Par exemple :

 
Sélectionnez
1.
2.
3.
function multiplierParDeux (nombre) {
  return nombre * 2;
}

Pour exécuter une fonction, il faut l'appeler en citant son nom, et en lui fournissant des valeurs pour chacun des paramètres entre parenthèses.

Par exemple :

Image non disponible
 
Sélectionnez
1.
var resultat = multiplierParDeux(3); // => le paramètre nombre vaut 3 => la variable resultat vaudra 6

Comme pour une variable, l'appel à une fonction sera remplacé la valeur qu'elle renvoie, au moment de l'exécution du programme. Contrairement aux variables, cette valeur dépendra de la valeur des paramètres passés à la fonction.

Ainsi, il est possible de passer le résultat de l'appel d'une fonction en paramètre d'une fonction.

Exemple de substitution d'un appel de fonction par sa valeur de retour :  :

Image non disponible
 
Sélectionnez
1.
2.
3.
4.
resultat = multiplierParDeux(multiplierParDeux(3)); // équivaut à :
resultat = multiplierParDeux(3 * 2); // qui équivaut à :
resultat = (3 * 2) * 2; // qui vaut finalement :
resultat = 12;

Et, avec une autre valeur passée en paramètre :

 
Sélectionnez
1.
2.
3.
4.
var resultat = multiplierParDeux(multiplierParDeux(4)); // équivaut à :
var resultat = multiplierParDeux(4 * 2); // qui équivaut à :
var resultat = (4 * 2) * 2; // qui vaut finalement :
var resultat = 16;

IV-A-3. Importance de return

Quand on exécute une fonction depuis une console JavaScript, la valeur retournée par cette fonction est affichée dans la console. Il ne faut pas pour autant confondre le mot-clé return et la fonction console.log.

En effet :

  • console.log peut être appelée plusieurs fois depuis une même définition de fonction, mais chaque appel de fonction ne peut résulter qu'en une seule valeur de retour spécifiée par return ;
  • l'usage de return permet à l'appelant d'une fonction de disposer de la valeur résultante comme il le souhaite : il peut par exemple décider d'afficher cette valeur dans la console, ou dans un alert, ou même de la stocker dans une variable. Or, si la définition de cette fonction affiche la valeur résultante dans la console au lieu d'utiliser return, il sera impossible pour l'appelant de récupérer cette valeur résultante dans son programme.

IV-B. Pratique  : Définition et appel de fonction en JavaScript

Dans cette partie de mise en pratique, nous allons définir ensemble plusieurs fonctions, et les tester en les appelant.

Développer :

  • une fonction diviserParDeux qui retourne la moitié de la valeur passée en paramètre. Tests  :

    • diviserParDeux(2) === 1;
    • diviserParDeux(4) === 2;
    • var n = Math.random(); diviserParDeux(n) === n / 2;
  • une fonction somme qui retourne la somme des deux paramètres qui lui seront passés. Tests  :

    • somme(1, 1) === 2;
    • somme(1, 2) === 3;
    • somme(2, 1) === 3;
    • var n = Math.random(); somme(n, 1) === n + 1;
  • une fonction signe qui retourne la chaine de caractères positif, négatif ou nul, selon le signe de la valeur passée en paramètre. Tests  :

    • signe(-1) === 'négatif';
    • signe(0) === 'nul';
    • signe(Math.random()) === 'positif';
  • une fonction factorielle qui retourne le produit de tous les entiers consécutifs entre 1 et l'entier passé en paramètre (compris). Exemple : factorielle(3) retourne le résultat de 1 * 2 * 3, soit 6. Tests  :

    • factorielle(0) === 1;
    • factorielle(1) === 1;
    • factorielle(3) === 6;
    • factorielle(4) === 24;

Solution

 
Cacher/Afficher le codeSélectionnez

IV-B-1. Bogues et tests unitaires : comment tester une fonction

Appeler une fonction ajoute de l'incertitude et parfois de l'imprévisibilité au comportement du code, car cela revient à déléguer une fonctionnalité à une autre partie du code (la définition de la fonction appelée).

Afin de se rassurer sur le bon fonctionnement d'une fonction et éviter les bogues, il est important de tester les fonctions qu'on utilise.

Un bogue est un comportement imprévu causant des anomalies et/ou l'interruption de l'exécution du programme. Il est généralement causé par une erreur d'implémentation ou une réalisation trop naïve (c.-à-d. ne couvrant pas certains cas qui peuvent se produire).

Exemple d'implémentation naïve pouvant causer un bogue :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
function multiplierParDix (nombre) {
  return nombre + '0'; // on ajoute un zéro à la fin du nombre
}
multiplierParDix(2);   // => 20 => OK
multiplierParDix(3);   // => 30 => OK
multiplierParDix(0.5); // => 0.50 => Bogue! on voulait obtenir 5 dans ce cas
Image non disponible

Dans l'exemple ci-dessus, nous avons effectué trois tests d'appel de notre fonction multiplierParDix, et l'un d'eux nous a permis de détecter un bogue dans notre fonction.

Afin de réduire le nombre de bogues potentiels d'une fonction, et donc de se rassurer sur son bon fonctionnement, il est important d'écrire et exécuter plusieurs tests unitaires, et penser intelligemment aux cas limites, les cas qui pourraient le plus probablement causer un bogue.

Écrire un test unitaire pour une fonction consiste à :

  • décrire un exemple d'usage de cette fonction, en précisant la valeur résultante attendue pour certaines valeurs de paramètres,
  • implémenter l'appel de cette fonction, et comparer la valeur résultante à celle qui est attendue.

Lors de l'exécution du test unitaire, si la valeur de la comparaison détermine si la fonction fonctionne comme prévu sur l'exemple de ce test.

Par exemple, on pourrait définir les trois tests unitaires suivants pour valider notre fonction multiplierParDix :

 
Sélectionnez
1.
2.
3.
multiplierParDix(2) === 20;  // => false (car '20' différent de 20)
multiplierParDix(3) === 30;  // => false (car '30' différent de 30)
multiplierParDix(0.5) === 5; // => false (car '0.50' différent de 0.5)

Avec la définition de la fonction multiplierParDix fournie plus haut, aucun de ces tests ne passe. C'est-à-dire que chaque test d'égalité sera false.

En revanche, les tests unitaires passeront avec la définition suivante de cette même fonction :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
function multiplierParDix (nombre) {
  return nombre * 10;
}
multiplierParDix(2) === 20;  // => true => OK
multiplierParDix(3) === 30;  // => true => OK
multiplierParDix(0.5) === 5; // => true => OK

À retenir : un test unitaire est un exemple d'appel permettant de vérifier qu'une fonction se comporte comme prévu dans un cas donné, en comparant le résultat effectivement retourné au résultat qui devrait être retourné.

IV-B-2. Valeur et affectation d'une fonction

Nous avons vu que l'appel d'une fonction consiste à mentionner son nom, suivi de paramètres exprimés entre parenthèses. Et que cet appel est remplacé par la valeur retournée par son exécution.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
// définition de la fonction multiplierParDeux()
function multiplierParDeux (nombre) {
  return nombre * 2;
}
// appel de la fonction multiplierParDeux(), en passant le nombre 3 en paramètre
var resultat = multiplierParDeux(3);
// la valeur retournée par l'appel de la fonction (6) est affectée à résultat

Ainsi, multiplierParDeux(3) est remplacé par sa valeur de retour : 6, après l'exécution de la fonction multiplierParDeux à laquelle on a passé la valeur littérale 3 comme valeur du paramètre appelé nombre.

Pour rappel, une variable JavaScript est remplacée par la dernière valeur qui lui a été affectée. Ainsi, si la valeur 6 a été affectée à la variable maVariable à l'aide de l'instruction maVariable = 6;, les mentions suivantes de maVariable seront remplacées par sa valeur 6.

En JavaScript, une fonction est une valeur, au même titre qu'un nombre ou une chaine de caractères. Elle peut donc aussi être attribuée à une variable.

Ainsi, il est possible d'affecter la fonction multiplierParDeux à la variable maVariable :

 
Sélectionnez
1.
maVariable = multiplierParDeux;

… et de l'appeler de la manière suivante :

 
Sélectionnez
1.
maVariable(3); // => retourne la valeur 6;

Il est donc aussi possible d'affecter une fonction anonyme à une variable :

 
Sélectionnez
1.
2.
3.
var multiplierParTrois = function (nombre) {
  return nombre * 3;
};

… ce qui est équivalent à écrire :

 
Sélectionnez
1.
2.
3.
function multiplierParTrois (nombre) {
  return nombre * 3;
}

IV-B-3. Exercice : Jeu ChiFouMi

IV-B-3-a. Fonctionnement du jeu à implémenter

À chaque manche, l'ordinateur et le joueur choisissent chacun un élément parmi pierre, feuille ou ciseaux.

Un point est donné à celui qui a choisi l'élément le plus fort, sachant que :

  • ciseaux > feuille (les ciseaux coupent la feuille)
  • pierre > ciseaux (la pierre casse les ciseaux)
  • feuille > pierre (la feuille enveloppe la pierre)

Si l'ordinateur et le joueur ont choisi le même élément, aucun d'eux n'emporte de point.

IV-B-3-b. Exemple de déroulement d'une manche

  • l'ordinateur choisit secrètement pierre (parmi les trois valeurs d'éléments possibles) ;
  • le joueur est invité à saisir son choix => il tape feuille ;
  • l'ordinateur affiche feuille, car c'est l'élément qui l'emporte (la feuille enveloppe la pierre).

IV-B-4. Phase 1 : Implémentation d'une manche

Pour implémenter le code d'une manche, nous allons :

  • définir une fonction comparer(choix1, choix2) qui renvoie le nom de l'élément gagnant, entre les deux passés en paramètres ;
  • appeler cette fonction, en passant les choix de l'ordinateur et du joueur en paramètres, afin de savoir lequel des deux a remporté la manche.

Voici une proposition d'étapes à suivre :

  1. Dessiner l'arbre de décision d'une manche : nom de l'élément gagnant en fonction de deux éléments choisis ;
  2. Transformer l'arbre de décision en conditions if imbriquées, en fonction de la valeur de deux variables : choix1 et choix2 ;
  3. Chaque condition de dernier niveau va afficher dans la console le nom de l'élément qui remporte la manche ;
  4. Transférer ces conditions dans la définition d'une fonction comparer(choix1, choix2) qui retourne le nom de l'élément gagnant à l'aide de return (au lieu de l'afficher dans la console), parmi les deux passés en paramètres ; Si les deux sont identiques, retourner égalité.
  5. Tester cette fonction en lui passant chaque combinaison possible de valeurs du jeu en paramètres ;
  6. En dehors de la définition de la fonction, créer les variables choixOrdi et choixUtilisateur ;
  7. Faire en sorte que choixOrdi ait pour valeur un des trois éléments, choisi de manière aléatoire, et que choixUtilisateur soit saisi par l'utilisateur à l'aide de prompt() ;
  8. Appeler la fonction comparer(), puis afficher dans la console la valeur de son résultat (l'élément qui remporte la manche), à partir des choix de l'ordinateur et du joueur.

IV-B-5. Phase 2 : Partie en trois manches, et scores

Après avoir implémenté une manche à l'aide de la fonction comparer(), faites en sorte que le joueur puisse jouer trois manches d'affilée et que le score final du joueur et de l'ordinateur soient affichés dans la console en fin de partie.

Pour cela :

  1. Créer les variables scoreOrdi et scoreJoueur ;
  2. Après l'affichage du résultat de l'appel à comparer() dans la console, incrémenter une de ces variables, en fonction de qui a remporté la manche ;
  3. Mettre le code correspondant à une manche dans une boucle for, de manière à ce qu'il s'exécute 3 fois d'affilée ;
  4. En fin de partie, afficher qui a remporté la partie : 'ordi', 'joueur' ou 'aucun', en fonction des scores.

Solution de la phase 1

 
Cacher/Afficher le codeSélectionnez

Solution de la phase 2

 
Cacher/Afficher le codeSélectionnez

précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2015 Adrien Joly. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.