Séance 9 — Les fonctions
Écrire une fois, utiliser partout
- Écrire une fonction avec des paramètres et un
return - Comprendre la différence entre
returnetconsole.log - Supprimer les répétitions de son code
1. Le problème, en vrai
Souvenez-vous du jeu du nombre mystère (séance 6) : cinq blocs de code quasiment identiques. Et du compteur de cafés (séance 5) : les mêmes trois lignes recopiées dans deux boutons.
Ce n’est pas seulement moche. C’est dangereux : le jour où vous voulez changer le message, vous devez le modifier à cinq endroits. Vous en oublierez un.
Ne jamais écrire deux fois la même chose.
Quand vous vous surprenez à copier-coller du code, arrêtez-vous : c’est le signal qu’il faut une fonction.
2. Une fonction, c’est une machine
Une fonction, c’est une machine :
entrées sortie
(paramètres) ──▶ ┌──────────────┐ ──▶ (return)
│ la machine │
3, 4 │ a + b │ 7
└──────────────┘
On la construit une fois. On l’utilise autant qu’on veut.
function additionner(a, b) {
return a + b;
}
console.log(additionner(3, 4)); // 7
console.log(additionner(10, 25)); // 35La forme
function additionner ( a , b ) {
└───┬───┘ └─────┬────┘ └──┬──┘
│ │ └── les PARAMÈTRES : ce qui entre
│ └──────────── le NOM de la fonction
└──────────────────────── mot-clé obligatoire
return a + b; ← ce qui SORT de la machine
}
function direBonjour(prenom) { // ① DÉFINITION : on construit la machine.
return `Bonjour ${prenom} !`; // Rien ne s'exécute ici !
}
const message = direBonjour("Camille"); // ② APPEL : on s'en sert
console.log(message); // Bonjour Camille !Écrire une fonction ne l’exécute pas. C’est comme écrire une recette de cuisine : tant que personne ne la suit, il n’y a pas de gâteau.
Étape 1 — Vos premières fonctions
app.js
function doubler(nombre) {
return nombre * 2;
}
function estMajeur(age) {
return age >= 18;
}
function saluer(prenom, ville) {
return `Salut ${prenom}, comment ça va à ${ville} ?`;
}
console.log(doubler(21)); // 42
console.log(estMajeur(15)); // false
console.log(saluer("Camille", "Palaiseau"));Remarquez que estMajeur renvoie un booléen : une fonction peut renvoyer n’importe quel type.
3. return n’est pas console.log
C’est la confusion de la séance. Prenez le temps.
function doubler(n) {
console.log(n * 2);
}
const resultat = doubler(5); // affiche 10
console.log(resultat); // undefined 😱La fonction affiche mais ne rend rien. Impossible de réutiliser le résultat.
function doubler(n) {
return n * 2;
}
const resultat = doubler(5); // n'affiche rien
console.log(resultat); // 10 ✅
console.log(doubler(5) + 1); // 11 ✅La fonction rend une valeur. On peut la stocker, la recalculer, la réutiliser.
console.log= parler à voix haute. Le son se perd.return= rendre un résultat à celui qui a demandé. Il peut s’en servir.
Une fonction qui console.log sans return est une machine qui affiche le résultat sur un écran… mais ne le donne à personne.
Règle du cours : une fonction calcule et renvoie. C’est celui qui l’appelle qui affiche.
return arrête tout de suite la fonction
function tester(n) {
return n * 2;
console.log("bonjour"); // ❌ jamais exécuté
}Dès que JavaScript rencontre return, il sort de la fonction. Le code après est mort.
C’est aussi très utile :
function categorie(age) {
if (age < 18) {
return "mineur"; // on sort ici…
}
return "majeur"; // …donc on n'arrive ici que si age >= 18
}Exercice 9.1
Écrivez trois fonctions :
carre(n)qui renvoien × nestPair(n)qui renvoietruesinest pairprixTTC(prixHT)qui renvoie le prix avec 20 % de TVA
Testez-les avec console.log.
app.js
function carre(n) {
return n * n;
}
function estPair(n) {
return n % 2 === 0;
}
function prixTTC(prixHT) {
return prixHT * 1.2;
}
console.log(carre(7)); // 49
console.log(estPair(10)); // true
console.log(estPair(7)); // false
console.log(prixTTC(100)); // 120Pour estPair, pas besoin de if ! n % 2 === 0 est déjà un booléen : on le renvoie directement. Écrire :
if (n % 2 === 0) { return true; } else { return false; }fonctionne, mais c’est trois fois plus long pour le même résultat.
4. Les fonctions fléchées
Vous les utilisez depuis la séance 5 sans le savoir. Voici la même fonction, écrite des deux façons :
// Version « function »
function doubler(n) {
return n * 2;
}
// Version fléchée — exactement la même chose
const doubler = (n) => {
return n * 2;
};const doubler = ( n ) => { return n * 2; };
└──┬───┘ └┬┘ └┬┘ └──────┬─────┘
│ │ │ └── le corps
│ │ └────────────── la flèche
│ └──────────────────── les paramètres
└───────────────────────────── le nom (c'est une variable !)
Pour des raisons historiques : function existe depuis 1995, la flèche depuis 2015. Aujourd’hui, les deux cohabitent et vous rencontrerez les deux.
Dans ce cours :
functionquand on écrit une fonction qui a un nom et qu’on réutilise- flèche quand on passe une fonction à quelque chose d’autre — typiquement
addEventListener
Vous comprenez maintenant cette ligne, écrite depuis la séance 5 :
bouton.addEventListener("click", () => {
…
});C’est une fonction sans nom et sans paramètre, qu’on donne à addEventListener pour qu’il l’exécute plus tard, au moment du clic. On l’appelle une fonction de rappel (callback).
5. Nettoyer le compteur de cafés
Étape 2 — Avant / après
Avant (séance 5) — les trois mêmes lignes deux fois :
ajouter.addEventListener("click", () => {
cafes = cafes + 1;
nombre.textContent = cafes;
cout.textContent = `Coût total : ${(cafes * PRIX_CAFE).toFixed(2)} €`;
});
reset.addEventListener("click", () => {
cafes = 0;
nombre.textContent = cafes;
cout.textContent = "Coût total : 0.00 €";
});Après — on isole « mettre l’affichage à jour » dans une fonction :
cafe.js
const PRIX_CAFE = 1.1;
let cafes = 0;
function afficher() {
nombre.textContent = cafes;
cout.textContent = `Coût total : ${(cafes * PRIX_CAFE).toFixed(2)} €`;
}
ajouter.addEventListener("click", () => {
cafes = cafes + 1;
afficher();
});
reset.addEventListener("click", () => {
cafes = 0;
afficher();
});
afficher(); // affichage initialMaintenant, si vous voulez changer le format du prix, il y a un seul endroit à modifier.
return, c’est permis ?
Oui. afficher() ne prend rien et ne rend rien : son travail est d’agir sur la page. On appelle ça un effet de bord, et c’est parfaitement normal pour une fonction d’affichage.
Notez les parenthèses vides obligatoires : afficher() l’appelle, afficher tout seul ne fait rien du tout (c’est juste le nom de la machine).
6. Attraper plusieurs éléments d’un coup
Pour enfin réparer le jeu du nombre mystère, il manque un outil :
const boutons = document.querySelectorAll(".choix");| Renvoie | |
|---|---|
querySelector |
le premier élément trouvé |
querySelectorAll |
tous les éléments, dans une liste parcourable |
for (const bouton of boutons) {
console.log(bouton.textContent);
}Étape 3 — Le nombre mystère, version courte
mystere.html
<button class="choix">1</button>
<button class="choix">2</button>
<button class="choix">3</button>
<button class="choix">4</button>
<button class="choix">5</button>
<p id="resultat">À toi de jouer.</p>Tous les boutons partagent la même classe choix.
mystere.js
const resultat = document.querySelector("#resultat");
const boutons = document.querySelectorAll(".choix");
function tirerSecret() {
return Math.floor(Math.random() * 5) + 1;
}
let secret = tirerSecret();
function jouer(choix) {
if (choix === secret) {
resultat.textContent = "Gagné ! 🎉";
resultat.className = "gagne";
secret = tirerSecret();
} else {
resultat.textContent = "Raté, essaie encore.";
resultat.className = "perdu";
}
}
for (const bouton of boutons) {
bouton.addEventListener("click", () => {
jouer(Number(bouton.textContent));
});
}Le même jeu, en trois fois moins de lignes. Et pour passer à 10 boutons, il suffit d’ajouter des <button class="choix"> dans le HTML : le JavaScript n’a pas besoin d’être touché.
Number(bouton.textContent) ?
textContent renvoie toujours du texte. Le bouton contient 3, mais on récupère "3".
Or "3" === 3 est faux (séance 6 !). Sans la conversion, on ne gagnerait jamais. C’est un bug très fréquent et difficile à voir : le code a l’air juste.
7. À toi de jouer
Exercice 9.2 — Prédire
Qu’affiche ce programme ?
function mystere(a, b) {
if (a > b) {
return a;
}
return b;
}
console.log(mystere(3, 8));
console.log(mystere(10, 2));
console.log(mystere(5, 5));Et à quoi sert cette fonction ? Trouvez-lui un meilleur nom.
8
10
5
La fonction renvoie le plus grand des deux nombres. Un bon nom serait plusGrand(a, b) ou maximum(a, b).
Pour mystere(5, 5) : 5 > 5 est faux, donc on passe au return b, qui vaut 5.
Ce qu’il faut retenir : un nom de fonction doit dire ce qu’elle fait. Quand on lit maximum(x, y) dans un programme, on comprend sans aller voir le code.
Exercice 9.3 — Une fonction qui utilise une boucle
Écrivez moyenne(notes) qui prend un tableau de nombres et renvoie leur moyenne.
console.log(moyenne([10, 20])); // 15
console.log(moyenne([12, 15, 8, 17])); // 13app.js
function moyenne(notes) {
let total = 0;
for (const note of notes) {
total = total + note;
}
return total / notes.length;
}
console.log(moyenne([10, 20])); // 15
console.log(moyenne([12, 15, 8, 17])); // 13Le return est après la boucle. S’il était à l’intérieur, la fonction sortirait dès le premier tour et renverrait un résultat faux.
Un paramètre peut donc être un tableau : c’est très courant.
Exercice 9.4 — Trouver les 3 erreurs
function saluer(prenom) {
console.log(`Bonjour ${prenom}`);
}
const message = saluer["Camille"];
console.log(message.length);
function triple(n) {
return;
n * 3;
}saluer["Camille"]→ on appelle une fonction avec des parenthèses, pas des crochets :saluer("Camille"). Les crochets servent aux tableaux.saluerne renvoie rien (elleconsole.log). Doncmessagevautundefined, etmessage.lengthprovoque une erreur. Il faut unreturn:function saluer(prenom) { return `Bonjour ${prenom}`; }return;puisn * 3;sur la ligne suivante →returnseul renvoieundefined, et la ligne d’après n’est jamais atteinte. La valeur doit être sur la même ligne que lereturn:function triple(n) { return n * 3; }
Exercice 9.5 — La calculatrice de pourboire 🧾
Faites une page pourboire.html avec :
- Un affichage du montant de l’addition, au départ
50 € - Deux boutons
+10 €et−10 €qui le modifient (jamais en dessous de 0) - Trois boutons
10 %,15 %,20 % - Un paragraphe qui affiche :
Pourboire : X € — Total : Y €
Contraintes :
- Une fonction
calculerPourboire(montant, pourcentage)qui renvoie le pourboire - Une fonction
afficher()qui met toute la page à jour - Aucune ligne de calcul dupliquée
pourboire.html
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8" />
<title>Pourboire</title>
<link rel="stylesheet" href="pourboire.css" />
</head>
<body>
<h1>Calculatrice de pourboire</h1>
<p>Addition : <span id="addition">50</span> €</p>
<button id="plus">+10 €</button>
<button id="moins">−10 €</button>
<p>Pourboire souhaité :</p>
<button class="taux" id="t10">10 %</button>
<button class="taux" id="t15">15 %</button>
<button class="taux" id="t20">20 %</button>
<p id="resultat"></p>
<script src="pourboire.js"></script>
</body>
</html>pourboire.js
const addition = document.querySelector("#addition");
const resultat = document.querySelector("#resultat");
const plus = document.querySelector("#plus");
const moins = document.querySelector("#moins");
const tauxBoutons = document.querySelectorAll(".taux");
let montant = 50;
let pourcentage = 10;
function calculerPourboire(montant, pourcentage) {
return (montant * pourcentage) / 100;
}
function afficher() {
const pourboire = calculerPourboire(montant, pourcentage);
const total = montant + pourboire;
addition.textContent = montant;
resultat.textContent =
`Pourboire (${pourcentage} %) : ${pourboire.toFixed(2)} € ` +
`— Total : ${total.toFixed(2)} €`;
}
plus.addEventListener("click", () => {
montant = montant + 10;
afficher();
});
moins.addEventListener("click", () => {
if (montant >= 10) {
montant = montant - 10;
afficher();
}
});
for (const bouton of tauxBoutons) {
bouton.addEventListener("click", () => {
pourcentage = Number(bouton.textContent.replace(" %", ""));
afficher();
});
}
afficher();Les points importants :
calculerPourboirefait un seul calcul et le renvoie. Elle ne touche pas à la page : on pourrait la réutiliser ailleurs.afficher()est le seul endroit qui écrit dans la page. Appelée à la fin de chaque action, et une fois au démarrage.- La boucle sur les trois boutons de taux évite trois blocs copiés-collés.
.replace(" %", "")transforme"10 %"en"10"avant la conversion en nombre. (Une solution plus élégante existe avec les attributsdata-: voir la fiche mémo JS.)
8. Fiche mémo
Définir
function nom(param1, param2) {
return quelqueChose;
}Appeler
const r = nom(valeur1, valeur2);Parenthèses obligatoires, même vides : afficher()
Version fléchée
const nom = (param) => {
return quelqueChose;
};return ≠ console.log
return x; // rend la valeur → réutilisable
console.log(x); // l'affiche → perduereturn arrête immédiatement la fonction.
Plusieurs éléments
const els = document.querySelectorAll(".classe");
for (const el of els) {
el.addEventListener("click", () => { … });
}Le piège
el.textContent est toujours du texte → Number(el.textContent)