Question 1Si tu déclares function double(n) { n * 2; } puis que tu exécutes console.log(double(4));, qu'est-ce qui s'affiche ?
Déclarations et expressions de fonction — arguments et return
Déclarations function, arguments et return, expressions de fonction, et pourquoi un return oublié donne undefined.
Si tu écris directement la formule du prix TTC à trois endroits — la liste des produits, le panier et la confirmation de commande —, un changement du taux de TVA t'oblige à corriger les trois, et l'écran que tu oublies continue d'afficher l'ancien montant.
Cet article traite des déclarations function, qui donnent un nom à un traitement pour pouvoir l'appeler, des expressions de fonction, qui rangent une fonction dans une variable comme une valeur, et de la valeur que renvoie return.
Nommer un traitement pour l'appeler — déclarations function et paramètres
Le calcul du prix TTC d'un produit est toujours le même ; seul le prix unitaire change. Comme la seule différence est le prix que tu transmets, tu peux donner un nom au calcul lui-même : la liste comme le panier n'ont plus qu'à « appeler ce nom ».
Une fonction (un bloc de code nommé que tu peux appeler autant de fois que tu veux) se déclare sous la forme function nom(paramètres) { corps }. Les paramètres entre parenthèses sont des variables qui reçoivent une valeur à chaque appel, et la valeur écrite après return (la valeur de retour) revient à l'endroit de l'appel.
// Donne le nom taxIncluded au calcul du prix TTC
function taxIncluded(price) {
const tax = Math.floor(price * 0.1);
return price + tax; // Renvoie la valeur calculée à l'appelant
}
// Appelle la même fonction avec des prix unitaires différents
console.log(taxIncluded(1200)); // 1320
console.log(taxIncluded(980)); // 1078
// Si tu oublies de passer une valeur, price reste undefined
console.log(taxIncluded()); // NaN
price change, la valeur renvoyée change aussi. Un appel sans valeur laisse price à undefined, et le résultat est NaN.price reçoit la valeur elle-même : que tu écrives 1200 directement ou que tu passes une variable comme itemPrice, la fonction se comporte exactement de la même façon.
Recevoir plusieurs arguments — la correspondance se fait par position
Quand le taux de remise dépend du statut du client ou de la promotion en cours, une fonction qui ne reçoit que le prix unitaire ne suffit plus. Si l'appelant transmet aussi le taux, le calcul reste écrit à un seul endroit et seul le taux est choisi au moment de l'appel.
Les paramètres se séparent par des virgules. Les valeurs de l'appel correspondent aux paramètres dans l'ordre où tu les écris : la première valeur va dans le premier paramètre, la deuxième dans le deuxième. La correspondance ne se fait pas par nom, donc si tu inverses l'ordre, le code reste valide et rien ne t'avertit.
// Reçoit un prix unitaire et un taux de remise, et renvoie le prix remisé
function applyDiscount(price, rate) {
return Math.floor(price * (1 - rate));
}
// La première valeur va dans price, la deuxième dans rate
console.log(applyDiscount(2400, 0.2)); // 1920
console.log(applyDiscount(2400, 0.05)); // 2280
// Même dans le mauvais ordre, le calcul s'exécute
console.log(applyDiscount(0.2, 2400)); // -480
applyDiscount, seul leur ordre change. Les inverser ne provoque aucune erreur : seul le résultat change.La ligne d'appel ne montre que des valeurs : en lisant applyDiscount(0.2, 2400), tu ne repères pas l'inversion. Quand tu obtiens une valeur impossible comme -480, compare l'ordre des valeurs de l'appel avec la définition de la fonction.
Traiter une fonction comme une valeur — expressions de fonction et variables
La livraison standard et la livraison express n'utilisent pas du tout la même formule. Plutôt que de préciser à chaque appel laquelle utiliser, tu peux ranger la bonne fonction dans une variable : l'appelant n'a plus qu'à appeler cette variable.
Une expression de fonction (une façon d'affecter une fonction à une variable comme une valeur) est une instruction d'affectation de la forme const nom = function (paramètres) { corps };. Une déclaration function est prête avant que le code commence à s'exécuter de haut en bas, alors que la variable d'une expression de fonction ne reçoit la fonction qu'au moment où la ligne d'affectation s'exécute (le mécanisme est expliqué dans l'article sur la portée et le hoisting).
// Une déclaration function peut être appelée depuis une ligne située avant elle
console.log(expressShipping(1.5)); // 900
function expressShipping(weight) {
return weight <= 2 ? 900 : 1300;
}
// Expression de fonction : on affecte une fonction à une variable comme une valeur
const normalShipping = function (weight) {
return weight <= 2 ? 500 : 800;
};
// Sans parenthèses, c'est la fonction elle-même qui va dans une autre variable
const feeRule = normalShipping;
console.log(feeRule(3)); // 800
console.log(typeof feeRule); // function
console.log(typeof normalShipping(3)); // number
ReferenceError. Une fonction rangée par une expression de fonction ne peut pas être appelée tant que la ligne d'affectation ne s'est pas exécutée.Le message d'erreur complet est ReferenceError: Cannot access 'normalShipping' before initialization. Regarde aussi la ligne feeRule du code ci-dessus : si tu affectes le nom d'une fonction sans parenthèses, c'est la fonction elle-même qui va dans l'autre variable.
Deux fonctions du même nom : c'est la dernière qui l'emporte
Comme les déclarations function sont préparées avant l'exécution, si tu en déclares deux avec le même nom, même un appel placé juste après la première exécute le corps de la seconde. Rien n'interrompt l'exécution, donc un doublon situé loin dans le fichier passe facilement inaperçu. Avec une expression de fonction en const, la seconde déclaration provoque une SyntaxError et le code ne démarre même pas.
Que se passe-t-il sans valeur de retour ? — le return oublié
Si une fonction contient un console.log, un texte s'affiche à l'écran quand tu l'appelles. Puisque quelque chose s'affiche, elle a l'air de fonctionner ; pourtant, si tu ranges sa valeur de retour dans une variable pour t'en servir, la chaîne attendue n'y est pas.
return renvoie une valeur et termine la fonction à cet endroit précis. Une fonction sans return renvoie undefined : afficher quelque chose et renvoyer une valeur sont deux actions distinctes. console.log ne fait qu'écrire à l'écran ; il ne transmet rien à l'appelant.
// Avec return : le texte revient à l'appelant
function formatLabel(name, stock) {
return `${name} (${stock} en stock)`;
console.log("Jamais atteinte"); // Placée après return, cette ligne ne s'exécute pas
}
// Sans return : ça s'affiche, mais la valeur de retour est undefined
function printLabel(name, stock) {
console.log(`${name} (${stock} en stock)`);
}
const label = formatLabel("Lampe de bureau", 3);
console.log(label); // Lampe de bureau (3 en stock)
const printed = printLabel("Hub USB", 5); // Hub USB (5 en stock)
console.log(printed); // undefined
| Écriture de la fonction | Ce qui se passe à l'appel | Ce que reçoit l'appelant |
|---|---|---|
| Renvoie le texte avec return | Le texte revient à l'appelant | Lampe de bureau (3 en stock) |
| Ne contient qu'un console.log | Affiche, mais ne renvoie rien | undefined |
| console.log après return | Lignes après return ignorées | Le texte revient quand même |
Si l'appelant doit se servir de la valeur, transmets-la avec return plutôt que de l'afficher.
Un retour à la ligne après return, et aucune valeur ne revient
Si tu passes à la ligne juste après return et que tu écris la valeur sur la ligne suivante, JavaScript considère que l'instruction se termine sur la ligne du return, et la fonction renvoie undefined. L'erreur arrive facilement quand tu déplaces un long littéral de gabarit sur sa propre ligne pour le rendre lisible. Commence toujours la valeur sur la même ligne que return.
Vérification des connaissances
Répondez à chaque question une par une.
Question 2Si tu appelles function fee(price, rate) { return price * rate; } avec fee(0.2, 1000), que reçoit price ?
Question 3Que se passe-t-il si tu appelles calc(1) sur une ligne située avant l'affectation const calc = function (n) { return n + 1; }; ?