Apprenez en lisant dans l'ordre

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
Trois appels différents à la même fonction
Définition detaxIncluded(price)taxIncluded(1200)taxIncluded(980)taxIncluded()price vaut 1200tax vaut 120price vaut 980tax vaut 98price vautundefinedtax vaut NaNRenvoie 1320Renvoie 1078Renvoie NaNpasse une valeurpasse une valeurne passe rien
Quand la valeur reçue par 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.

Tu vas afficher la durée d'une formation sous la forme « X h Y min ». lectureMinutes et practiceMinutes sont déjà déclarées.

① Déclare une fonction qui prend un nombre de minutes et renvoie une chaîne de la forme « X h Y min ».

② Affiche la durée du cours sous la forme « Cours : X h Y min ».

③ Affiche la durée des travaux pratiques sous la forme « TP : X h Y min ».

④ Affiche la durée totale des deux sous la forme « Total : X h Y min ».

(Si le code s'exécute correctement, une explication s'affiche.)

Éditeur JavaScript / TypeScript

Exécuter le code pour voir le résultat

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
Les arguments correspondent par position
Passer(2400, 0.2)price vaut 2400rate vaut 0.2Calcule2400 × 0.8Renvoie 1920Passer(0.2, 2400)price vaut 0.2rate vaut 2400Calcule0.2 × -2399Renvoie -480
Les deux mêmes valeurs passées à 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.

Tu vas calculer le montant à payer d'une commande avec deux fonctions. unitPrice, quantity, shippingFee et couponAmount sont déjà déclarées.

① Déclare une fonction qui prend un prix unitaire et une quantité, et renvoie le sous-total.

② Déclare une fonction qui prend, dans cet ordre, le sous-total, les frais de port et la remise, et renvoie le montant à payer.

③ Passe la valeur de retour de ① à ② et affiche « Montant à payer : X yens ».

④ Mets les frais de port à 0 et affiche « Avec la livraison gratuite : X yens ».

Éditeur JavaScript / TypeScript

Exécuter le code pour voir le résultat

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
Peut-on l'appeler depuis une ligne située avant ?
Écrite avec unedéclarationfunctionAppelée avantla déclarationPrête avantl'exécutionRenvoie 900Rangée dans unevariable par uneexpressionAppelée avantl'affectationLa variable n'apas encore reçula fonctionS'arrête sur uneReferenceError
Un appel placé avant l'affectation s'arrête sur une 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.

Avec et sans parenthèses
feeRule =normalShippingLa fonctionelle-même y vatypeof donnefunctionAppelable plustard : feeRule(3)feeRule =normalShipping(3)Le corps s'exécuteet 800 y vatypeof donnenumberfeeRule(3) :TypeError
Sans parenthèses, c'est la fonction elle-même qui va dans la variable ; avec, c'est le résultat de son exécution. Si tu ajoutes des parenthèses à une fonction que tu voulais appeler plus tard, il ne te reste que sa valeur de retour.

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.

Tu vas choisir le calcul des frais de paiement selon le type d'abonnement du client. amount et isPremium sont déjà déclarées.

① Écris standardFee, qui renvoie des frais de 3 %, et premiumFee, qui renvoie des frais de 1 %, sous forme d'expressions de fonction (arrondi à l'entier inférieur).

② Choisis l'une des deux selon isPremium et range-la dans applyFee.

③ Appelle applyFee et affiche « Frais : X yens ».

④ Appelle standardFee directement et affiche « Pour un membre standard : X yens ».

Éditeur JavaScript / TypeScript

Exécuter le code pour voir le résultat

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 fonctionCe qui se passe à l'appelCe que reçoit l'appelant
Renvoie le texte avec returnLe texte revient à l'appelantLampe de bureau (3 en stock)
Ne contient qu'un console.logAffiche, mais ne renvoie rienundefined
console.log après returnLignes après return ignoréesLe 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.

Tu vas ajouter les frais de port pour obtenir le montant à payer. orderTotal, largeOrderTotal et shippingFee (une fonction censée renvoyer les frais de port) sont déjà déclarées.

① Affiche orderTotal plus les frais de port sous la forme « Montant à payer : X yens ».

② Affiche largeOrderTotal sous la même forme.

③ Déclare shippingFeeFixed, qui renvoie les frais de port sous forme de nombre quel que soit le montant.

④ Refais l'affichage de ① avec shippingFeeFixed.

Éditeur JavaScript / TypeScript

Exécuter le code pour voir le résultat
QUIZ

Vérification des connaissances

Répondez à chaque question une par une.

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 ?

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; }; ?