Très souvent, nous devons effectuer une action similaire à de nombreux endroits du script.
Par exemple, nous devons afficher un message attrayant lorsqu'un visiteur se connecte, se déconnecte et peut-être ailleurs.
Les fonctions sont les principaux « éléments de base » du programme. Ils permettent d'appeler le code plusieurs fois sans répétition.
Nous avons déjà vu des exemples de fonctions intégrées, comme alert(message)
, prompt(message, default)
et confirm(question)
. Mais nous pouvons également créer nos propres fonctions.
Pour créer une fonction, nous pouvons utiliser une déclaration de fonction .
Cela ressemble à ceci :
fonction showMessage() { alert( 'Bonjour à tous !' ); }
Le mot clé function
va en premier, puis vient le nom de la fonction , puis une liste de paramètres entre parenthèses (séparés par des virgules, vides dans l'exemple ci-dessus, nous verrons des exemples plus tard) et enfin le code de la fonction, également nommé « le corps de fonction », entre accolades.
nom de la fonction (paramètre1, paramètre2, ... paramètreN) { // corps }
Notre nouvelle fonction peut être appelée par son nom : showMessage()
.
Par exemple:
fonction showMessage() { alert( 'Bonjour à tous !' ); } showMessage(); showMessage();
L'appel showMessage()
exécute le code de la fonction. Ici, nous verrons le message deux fois.
Cet exemple démontre clairement l’un des principaux objectifs des fonctions : éviter la duplication de code.
Si jamais on a besoin de changer le message ou la façon dont il est affiché, il suffit de modifier le code à un seul endroit : la fonction qui le génère.
Une variable déclarée dans une fonction n'est visible qu'à l'intérieur de cette fonction.
Par exemple:
fonction showMessage() { let message = "Bonjour, je suis JavaScript !"; // variable locale alerte(message); } showMessage(); // Bonjour, je suis JavaScript ! alerte(message); // <-- Erreur ! La variable est locale à la fonction
Une fonction peut également accéder à une variable externe, par exemple :
laissez userName = 'John'; fonction showMessage() { let message = 'Bonjour,' + nom d'utilisateur ; alerte (message); } showMessage(); // Bonjour, Jean
La fonction a un accès complet à la variable externe. Il peut également le modifier.
Par exemple:
laissez userName = 'John'; fonction showMessage() { Nom d'utilisateur = "Bob" ; // (1) a changé la variable externe let message = 'Bonjour,' + nom d'utilisateur ; alerte (message); } alert( nomutilisateur ); // John avant l'appel de la fonction showMessage(); alert( nomutilisateur ); // Bob, la valeur a été modifiée par la fonction
La variable externe n'est utilisée que s'il n'y en a pas de locale.
Si une variable du même nom est déclarée à l'intérieur de la fonction, elle masque la variable externe. Par exemple, dans le code ci-dessous, la fonction utilise le userName
local. L'extérieur est ignoré :
laissez userName = 'John'; fonction showMessage() { laissez nomutilisateur = "Bob" ; // déclare une variable locale let message = 'Bonjour,' + nom d'utilisateur ; // Bob alerte (message); } // la fonction créera et utilisera son propre nom d'utilisateur showMessage(); alert( nomutilisateur ); // John, inchangé, la fonction n'a pas accédé à la variable externe
Variables globales
Les variables déclarées en dehors de toute fonction, telles que le userName
externe dans le code ci-dessus, sont appelées global .
Les variables globales sont visibles depuis n'importe quelle fonction (sauf si elles sont masquées par des variables locales).
C'est une bonne pratique de minimiser l'utilisation de variables globales. Le code moderne a peu ou pas de globals. La plupart des variables résident dans leurs fonctions. Parfois cependant, ils peuvent être utiles pour stocker des données au niveau du projet.
Nous pouvons transmettre des données arbitraires aux fonctions en utilisant des paramètres.
Dans l'exemple ci-dessous, la fonction a deux paramètres : from
et text
.
function showMessage(from, texte) { // paramètres : from, texte alerte(de + ': ' + texte); } showMessage('Anne', 'Bonjour !'); //Anne : Bonjour ! (*) showMessage('Ann', "Quoi de neuf ?"); // Ann : Quoi de neuf ? (**)
Lorsque la fonction est appelée dans les lignes (*)
et (**)
, les valeurs données sont copiées dans les variables locales from
et text
. Ensuite, la fonction les utilise.
Voici un autre exemple : nous prenons une variable from
et la transmettons à la fonction. Attention : la fonction change from
, mais le changement n'est pas visible à l'extérieur, car une fonction obtient toujours une copie de la valeur :
fonction showMessage (de, texte) { de = '*' + de + '*'; // rend "from" plus joli alert( from + ': ' + texte ); } laissez from = "Ann"; showMessage(de, "Bonjour"); // *Ann* : Bonjour // la valeur de "from" est la même, la fonction a modifié une copie locale alerte( de ); //Anne
Lorsqu'une valeur est passée en tant que paramètre de fonction, elle est également appelée argument .
En d’autres termes, pour mettre ces termes au clair :
Un paramètre est la variable répertoriée entre parenthèses dans la déclaration de fonction (c'est un terme temporel de déclaration).
Un argument est la valeur qui est transmise à la fonction lorsqu'elle est appelée (c'est un terme au moment de l'appel).
Nous déclarons des fonctions listant leurs paramètres, puis les appelons en passant des arguments.
Dans l'exemple ci-dessus, on pourrait dire : « la fonction showMessage
est déclarée avec deux paramètres, puis appelée avec deux arguments : from
et "Hello"
».
Si une fonction est appelée mais qu'aucun argument n'est fourni, alors la valeur correspondante devient undefined
.
Par exemple, la fonction showMessage(from, text)
susmentionnée peut être appelée avec un seul argument :
showMessage("Anne");
Ce n'est pas une erreur. Un tel appel afficherait "*Ann*: undefined"
. Comme la valeur de text
n'est pas transmise, elle devient undefined
.
Nous pouvons spécifier la valeur dite « par défaut » (à utiliser en cas d'omission) pour un paramètre dans la déclaration de fonction, en utilisant =
:
function showMessage(from, text = "aucun texte donné") { alert( from + ": " + texte ); } showMessage("Anne"); // Ann : aucun texte donné
Désormais, si le paramètre text
n'est pas passé, il obtiendra la valeur "no text given"
.
La valeur par défaut intervient également si le paramètre existe, mais est strictement égal undefined
, comme ceci :
showMessage("Ann", non défini); // Ann : aucun texte donné
Ici, "no text given"
est une chaîne, mais il peut s'agir d'une expression plus complexe, qui n'est évaluée et attribuée que si le paramètre est manquant. Donc c'est aussi possible :
function showMessage (de, texte = autreFonction()) { // anotherFunction() exécuté uniquement si aucun texte n'est donné // son résultat devient la valeur du texte }
Évaluation des paramètres par défaut
En JavaScript, un paramètre par défaut est évalué à chaque fois que la fonction est appelée sans le paramètre correspondant.
Dans l'exemple ci-dessus, anotherFunction()
n'est pas appelée du tout si le paramètre text
est fourni.
D'un autre côté, il est appelé indépendamment chaque fois qu'il manque text
.
Paramètres par défaut dans l'ancien code JavaScript
Il y a plusieurs années, JavaScript ne prenait pas en charge la syntaxe des paramètres par défaut. Les gens ont donc utilisé d’autres moyens pour les spécifier.
De nos jours, on peut les retrouver dans des scripts anciens.
Par exemple, une vérification explicite pour undefined
:
fonction showMessage (de, texte) { si (texte === non défini) { text = 'aucun texte donné'; } alert( from + ": " + texte ); }
…Ou en utilisant le ||
opérateur:
fonction showMessage (de, texte) { // Si la valeur du texte est fausse, attribuez la valeur par défaut // cela suppose que text == "" équivaut à pas de texte du tout texte = texte || « aucun texte donné » ; ... }
Parfois, il est judicieux d'attribuer des valeurs par défaut aux paramètres ultérieurement après la déclaration de la fonction.
On peut vérifier si le paramètre est passé lors de l'exécution de la fonction, en le comparant avec undefined
:
fonction showMessage (texte) { //... if (text === undefined) { // si le paramètre est manquant texte = 'message vide' ; } alerte (texte); } showMessage(); // message vide
…Ou nous pourrions utiliser le ||
opérateur:
fonction showMessage (texte) { // si le texte n'est pas défini ou est faux, définissez-le sur "vide" texte = texte || 'vide'; ... }
Les moteurs JavaScript modernes prennent en charge l'opérateur de fusion nul ??
, il est préférable que la plupart des valeurs fausses, telles que 0
, soient considérées comme « normales » :
fonction showCount(compte) { // si le nombre est indéfini ou nul, affiche "inconnu" alert(count ?? "inconnu"); } showCount(0); // 0 showCount(null); // inconnu showCount(); // inconnu
Une fonction peut renvoyer une valeur dans le code appelant comme résultat.
L'exemple le plus simple serait une fonction qui additionne deux valeurs :
fonction somme(a, b) { renvoyer a + b ; } soit résultat = somme (1, 2); alerte( résultat ); // 3
La directive return
peut être à n'importe quel endroit de la fonction. Lorsque l'exécution l'atteint, la fonction s'arrête et la valeur est renvoyée au code appelant (attribué au result
ci-dessus).
Il peut y avoir plusieurs occurrences de return
dans une seule fonction. Par exemple:
fonction checkAge(age) { si (âge >= 18) { renvoie vrai ; } autre { return confirm('Avez-vous la permission de vos parents ?'); } } let age = prompt('Quel âge as-tu ?', 18); si ( checkAge(age) ) { alert( 'Accès accordé' ); } autre { alert( 'Accès refusé' ); }
Il est possible d'utiliser return
sans valeur. Cela provoque la fermeture immédiate de la fonction.
Par exemple:
fonction showMovie (âge) { si ( !checkAge(age) ) { retour; } alert( "Je vous montre le film" ); // (*) //... }
Dans le code ci-dessus, si checkAge(age)
renvoie false
, alors showMovie
ne procédera pas à l' alert
.
Une fonction avec un return
vide ou sans retour undefined
Si une fonction ne renvoie pas de valeur, c'est comme si elle renvoyait undefined
:
function doNothing() { /* vide */ } alert( doNothing() === non défini ); // vrai
Un return
vide est également identique à return undefined
:
fonction ne rien faire() { retour; } alert( doNothing() === non défini ); // vrai
N'ajoutez jamais de nouvelle ligne entre return
et la valeur
Pour une expression longue en return
, il peut être tentant de la mettre sur une ligne distincte, comme ceci :
retour (certains + long + expression + ou + peu importe * f(a) + f(b))
Cela ne fonctionne pas, car JavaScript suppose un point-virgule après return
. Cela fonctionnera de la même manière que :
retour; (certains + long + expression + ou + peu importe * f(a) + f(b))
Cela devient donc effectivement un retour vide.
Si nous voulons que l'expression renvoyée s'étende sur plusieurs lignes, nous devons la démarrer sur la même ligne que return
. Ou au moins, mettez-y les parenthèses ouvrantes comme suit :
retour ( un peu + long + expression + ou + peu importe * f(a) + f(b) )
Et cela fonctionnera exactement comme nous l’espérons.
Les fonctions sont des actions. Leur nom est donc généralement un verbe. Il doit être bref, aussi précis que possible et décrire ce que fait la fonction, afin que quelqu'un qui lit le code ait une indication de ce que fait la fonction.
Il est courant de commencer une fonction par un préfixe verbal qui décrit vaguement l'action. Il doit y avoir un accord au sein de l'équipe sur la signification des préfixes.
Par exemple, les fonctions commençant par "show"
affichent généralement quelque chose.
Fonction commençant par…
"get…"
– renvoie une valeur,
"calc…"
– calculer quelque chose,
"create…"
– créer quelque chose,
"check…"
– vérifie quelque chose et renvoie un booléen, etc.
Exemples de tels noms :
showMessage(..) // affiche un message getAge(..) // renvoie l'âge (l'obtient d'une manière ou d'une autre) calcSum(..) // calcule une somme et renvoie le résultat createForm(..) // crée un formulaire (et le renvoie généralement) checkPermission(..) // vérifie une autorisation, renvoie vrai/faux
Avec les préfixes en place, un coup d'œil sur le nom d'une fonction permet de comprendre quel type de travail elle effectue et quel type de valeur elle renvoie.
Une fonction – une action
Une fonction doit faire exactement ce qui est suggéré par son nom, pas plus.
Deux actions indépendantes méritent généralement deux fonctions, même si elles sont généralement appelées ensemble (dans ce cas on peut créer une 3ème fonction qui appelle ces deux).
Quelques exemples de non-respect de cette règle :
getAge
– ce serait mauvais s'il affichait une alert
avec l'âge (ne devrait être obtenu).
createForm
– serait mauvais s'il modifiait le document en y ajoutant un formulaire (il devrait seulement le créer et le renvoyer).
checkPermission
– serait mauvais s’il affiche le message access granted/denied
(doit uniquement effectuer la vérification et renvoyer le résultat).
Ces exemples supposent des significations courantes des préfixes. Vous et votre équipe êtes libres de vous mettre d’accord sur d’autres significations, mais elles ne sont généralement pas très différentes. Dans tous les cas, vous devez bien comprendre ce que signifie un préfixe, ce qu'une fonction préfixée peut et ne peut pas faire. Toutes les fonctions portant le même préfixe doivent obéir aux règles. Et l'équipe doit partager les connaissances.
Noms de fonctions ultra-courts
Les fonctions très souvent utilisées portent parfois des noms ultracourts.
Par exemple, le framework jQuery définit une fonction avec $
. La bibliothèque Lodash a sa fonction principale nommée _
.
Ce sont des exceptions. En général, les noms de fonctions doivent être concis et descriptifs.
Les fonctions doivent être courtes et faire exactement une chose. Si cette chose est grande, cela vaut peut-être la peine de diviser la fonction en quelques fonctions plus petites. Parfois, suivre cette règle n’est pas si simple, mais c’est certainement une bonne chose.
Une fonction distincte est non seulement plus facile à tester et à déboguer – son existence même est un excellent commentaire !
Par exemple, comparez les deux fonctions showPrimes(n)
ci-dessous. Chacun génère des nombres premiers jusqu'à n
.
La première variante utilise une étiquette :
fonction showPrimes(n) { nextPrime : pour (soit i = 2 ; i < n ; i++) { pour (soit j = 2; j < i; j++) { si (i % j == 0) continue nextPrime ; } alerte( je ); // un premier } }
La deuxième variante utilise une fonction supplémentaire isPrime(n)
pour tester la primalité :
fonction showPrimes(n) { pour (soit i = 2; i < n; i++) { if (!isPrime(i)) continue ; alerte(i); // un premier } } la fonction estPrime(n) { pour (soit i = 2; i < n; i++) { if ( n % i == 0) renvoie false ; } renvoie vrai ; }
La deuxième variante est plus facile à comprendre, n'est-ce pas ? Au lieu du morceau de code, nous voyons le nom de l'action ( isPrime
). Parfois, les gens qualifient ce code d' auto-description .
Ainsi, des fonctions peuvent être créées même si nous n'avons pas l'intention de les réutiliser. Ils structurent le code et le rendent lisible.
Une déclaration de fonction ressemble à ceci :
nom de la fonction (paramètres, délimités, par, virgule) { /* code */ }
Les valeurs transmises à une fonction en tant que paramètres sont copiées dans ses variables locales.
Une fonction peut accéder à des variables externes. Mais cela ne fonctionne que de l’intérieur vers l’extérieur. Le code en dehors de la fonction ne voit pas ses variables locales.
Une fonction peut renvoyer une valeur. Si ce n'est pas le cas, alors son résultat est undefined
.
Pour rendre le code clair et facile à comprendre, il est recommandé d'utiliser principalement des variables et des paramètres locaux dans la fonction, et non des variables externes.
Il est toujours plus facile de comprendre une fonction qui obtient des paramètres, travaille avec eux et renvoie un résultat qu'une fonction qui n'obtient aucun paramètre, mais modifie les variables externes comme effet secondaire.
Dénomination de la fonction :
Un nom doit décrire clairement ce que fait la fonction. Lorsque nous voyons un appel de fonction dans le code, un bon nom nous permet instantanément de comprendre ce qu'il fait et ce qu'il renvoie.
Une fonction est une action, donc les noms de fonctions sont généralement verbaux.
Il existe de nombreux préfixes de fonctions bien connus comme create…
, show…
, get…
, check…
et ainsi de suite. Utilisez-les pour indiquer ce que fait une fonction.
Les fonctions sont les principaux éléments constitutifs des scripts. Nous avons maintenant couvert les bases, nous pouvons donc commencer à les créer et à les utiliser. Mais ce n'est que le début du chemin. Nous y reviendrons plusieurs fois, en approfondissant leurs fonctionnalités avancées.
importance : 4
La fonction suivante renvoie true
si le paramètre age
est supérieur à 18
.
Sinon il demande une confirmation et renvoie son résultat :
fonction checkAge(age) { si (âge > 18) { renvoie vrai ; } autre { //... return confirm('Les parents vous ont-ils autorisé ?'); } }
La fonction fonctionnera-t-elle différemment si else
est supprimé ?
fonction checkAge(age) { si (âge > 18) { renvoie vrai ; } //... return confirm('Les parents vous ont-ils autorisé ?'); }
Y a-t-il une différence dans le comportement de ces deux variantes ?
Aucune différence !
Dans les deux cas, return confirm('Did parents allow you?')
s'exécute exactement lorsque la condition if
est fausse.
importance : 4
La fonction suivante renvoie true
si le paramètre age
est supérieur à 18
.
Sinon, il demande une confirmation et renvoie son résultat.
fonction checkAge(age) { si (âge > 18) { renvoie vrai ; } autre { return confirm('Les parents vous ont-ils autorisé ?'); } }
Réécrivez-le, pour faire la même chose, mais sans if
, sur une seule ligne.
Faites deux variantes de checkAge
:
Utiliser un opérateur de point d'interrogation ?
Utiliser OU ||
En utilisant un opérateur de point d'interrogation '?'
:
fonction checkAge(age) { retour (âge > 18) ? true : confirm('Les parents vous ont-ils autorisé ?'); }
Utiliser OU ||
(la variante la plus courte) :
fonction checkAge(age) { retour (âge > 18) || confirm('Les parents vous ont-ils permis ?'); }
Notez que les parenthèses autour age > 18
ne sont pas obligatoires ici. Ils existent pour une meilleure lisibilité.
importance : 1
Écrivez une fonction min(a,b)
qui renvoie le plus petit des deux nombres a
et b
.
Par exemple:
min(2, 5) == 2 min(3, -1) == -1 min(1, 1) == 1
Une solution utilisant if
:
fonction min(a, b) { si (une < b) { renvoyer un ; } autre { retourner b ; } }
Une solution avec un opérateur de point d'interrogation '?'
:
fonction min(a, b) { retourner un < b ? une : b ; }
PS Dans le cas d'une égalité a == b
peu importe ce qu'il faut retourner.
importance : 4
Écrivez une fonction pow(x,n)
qui renvoie x
en puissance n
. Ou, en d’autres termes, multiplie x
par lui-même n
fois et renvoie le résultat.
po(3, 2) = 3 * 3 = 9 pow(3, 3) = 3 * 3 * 3 = 27 pow(1, 100) = 1 * 1 * ...* 1 = 1
Créez une page Web qui demande x
et n
, puis affiche le résultat de pow(x,n)
.
Exécutez la démo
PS Dans cette tâche, la fonction ne doit prendre en charge que les valeurs naturelles de n
: entiers à partir de 1
.
fonction pow(x, n) { soit le résultat = x ; pour (soit i = 1; i < n; i++) { résultat *= x ; } renvoyer le résultat ; } let x = prompt("x?", ''); let n = prompt("n?", ''); si (n < 1) { alert(`Power ${n} n'est pas pris en charge, utilisez un entier positif`); } autre { alerte( pow(x, n) ); }