Très souvent, nous devons effectuer une action similaire à plusieurs endroits du script.
Par exemple, nous devons afficher un beau message lorsquâun visiteur se connecte, se déconnecte et peut-être ailleurs.
Les fonctions sont les principales âcomposantesâ du programme. Ils permettent au code dâêtre appelé plusieurs fois sans répétition.
Nous avons déjà vu des exemples de fonctions intégrées, telles que alert(message), prompt(message, default) et confirm(question). Mais nous pouvons aussi créer nos propres fonctions.
Déclaration de fonction
Pour créer une fonction, nous pouvons utiliser une déclaration de fonction.
Cela ressemble à ceci :
function showMessage() {
alert( 'Hello everyone!' );
}
Le mot-clé function commence en premier, puis le nom de la fonction, puis une liste de paramètres entre les 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 appelé âle corps de la fonctionâ, entre des accolades.
function name(parameter1, parameter2, ... parameterN) {
// body
}
Notre nouvelle fonction peut être appelée par son nom : showMessage().
Par exemple :
function showMessage() {
alert( 'Hello everyone!' );
}
showMessage();
showMessage();
Lâappel showMessage() exécute le code de la fonction. Ici, nous verrons le message deux fois, parce quâon lâappelle deux fois.
Cet exemple illustre clairement lâun des principaux objectifs des fonctions: éviter la duplication de code.
Si nous devons un jour modifier le message ou son affichage, il suffit de modifier le code à un endroit: la fonction qui le renvoie.
Variables locales
Une variable déclarée à lâintérieur dâune fonction nâest visible quâà lâintérieur de cette fonction.
Par exemple :
function showMessage() {
let message = "Hello, I'm JavaScript!"; // variable locale
alert( message );
}
showMessage(); // Hello, I'm JavaScript!
alert( message ); // <-- Erreur! La variable est locale à la fonction
Variables externes
Une fonction peut également accéder à une variable externe, par exemple :
let userName = 'John';
function showMessage() {
let message = 'Hello, ' + userName;
alert(message);
}
showMessage(); // Hello, John
La fonction a un accès complet à la variable externe. Cela peut aussi la modifier.
Par exemple :
let userName = 'John';
function showMessage() {
userName = "Bob"; // (1) changé la variable externe
let message = 'Hello, ' + userName;
alert(message);
}
alert( userName ); // John avant l'appel de fonction
showMessage();
alert( userName ); // Bob, la valeur a été modifiée par la fonction
La variable externe nâest utilisée que sâil nây a pas de variable locale.
Si une variable du même nom est déclarée à lâintérieur de la fonction, elle eclipsera la variable externe. Par exemple, dans le code ci-dessous, la fonction utilise le nom userName local. Lâexterne est ignoré :
let userName = 'John';
function showMessage() {
let userName = "Bob"; // déclarer une variable locale
let message = 'Hello, ' + userName; // Bob
alert(message);
}
// la fonction créera et utilisera son propre userName
showMessage();
alert( userName ); // John, inchangé, la fonction n'a pas accédé à la variable externe
Les variables déclarées en dehors de toute fonction, telle que userName externe dans le code ci-dessus, sont appelées globales.
Les variables globales sont visibles depuis nâimporte quelle fonction (sauf si elles sont masquées par les variables locales).
Câest une bonne pratique de minimiser lâutilisation de variables globales. Le code moderne a peu ou pas de variable globales. La plupart des variables résident dans leurs fonctions. Parfois, cependant, ils peuvent être utiles pour stocker des données au niveau du projet.
Arguments
Nous pouvons transmettre des données arbitraires à des fonctions à lâaide de paramètres.
Dans lâexemple ci-dessous, la fonction a deux paramètres: from et text.
function showMessage(from, text) { // arguments : from, text
alert(from + ': ' + text);
}
showMessage('Ann', 'Hello!'); // Ann: Hello! (*)
showMessage('Ann', "What's up?"); // Ann: What's up? (**)
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 avons une variable from et la transmettons à la fonction. Remarque : la fonction change from, mais le changement nâest pas visible à lâextérieur, car une fonction obtient toujours une copie de la valeur :
function showMessage(from, text) {
from = '*' + from + '*'; // améliore l'apparence de "from"
alert( from + ': ' + text );
}
let from = "Ann";
showMessage(from, "Hello"); // *Ann*: Hello
// la valeur de "from" est la même, la fonction a modifié une copie locale
alert( from ); // Ann
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 fonction déclaration (câest un terme du temps de la déclaration).
- Un argument est la valeur qui est transmise à la fonction lorsquâelle est appelée (câest un terme du temps de lâappel).
Nous déclarons des fonctions en 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".
Les valeurs par défaut
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) mentionnée précédemment peut être appelée avec un seul argument :
showMessage("Ann");
Ce nâest pas une erreur. Un tel appel produirait "*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 si omise) pour un paramètre dans la déclaration de fonction, en utilisant = :
function showMessage(from, text = "no text given") {
alert( from + ": " + text );
}
showMessage("Ann"); // Ann: no text given
Maintenant, si le paramètre text nâest pas passé, il obtiendra la valeur "no text given".
La valeur par défaut saute également si le paramètre existe, mais est strictement égal à undefined, comme ceci :
showMessage("Ann", undefined); // Ann: no text given
Ici, "no text given" est une chaîne de caractères, mais il peut sâagir dâune expression plus complexe, qui nâest évaluée et affectée que si le paramètre est manquant. Donc, cela est également possible :
function showMessage(from, text = anotherFunction()) {
// anotherFunction() est exécuté uniquement si aucun texte n'est fourni
// son résultat devient la valeur de text
}
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 du tout appelé, si le paramètre text est fourni.
Dâun autre côté, il est appelé indépendamment à chaque fois que text est manquant.
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 croiser dans dâanciens scripts.
Par exemple, une vérification explicite pour undefined :
function showMessage(from, text) {
if (text === undefined) {
text = 'no text given';
}
alert( from + ": " + text );
}
â¦Ou en utilisant lâopérateur || :
function showMessage(from, text) {
// Si la valeur du texte est fausse, attribuez la valeur par défaut
// cela suppose que text == "" est identique à pas de texte du tout
text = text || 'no text given';
...
}
Paramètres par défaut alternatifs
Il est parfois judicieux de définir des valeurs par défaut pour les paramètres non pas dans la fonction déclaration, mais à un stade ultérieur, lors de son exécution.
Nous pouvons vérifier si le paramètre est passé lors de lâexécution de la fonction, en le comparant avec undefined :
function showMessage(text) {
// ...
if (text === undefined) { // si le paramètre est manquant
text = 'empty message';
}
alert(text);
}
showMessage(); // empty message
â¦Ou nous pourrions utiliser lâopérateur || :
function showMessage(text) {
// if text is undefined or otherwise falsy, set it to 'empty'
text = text || 'empty';
...
}
Les moteurs JavaScript modernes prennent en charge lâopérateur de coalescence des nuls ??, câest mieux quand des valeurs fausses, telles que 0, sont considérées comme ânormalesâ :
function showCount(count) {
// if count is undefined or null, show "unknown"
alert(count ?? "unknown");
}
showCount(0); // 0
showCount(null); // unknown
showCount(); // unknown
Renvoyer une valeur
Une fonction peut renvoyer une valeur dans le code appelant en tant que résultat.
Lâexemple le plus simple serait une fonction qui additionne deux valeurs :
function sum(a, b) {
return a + b;
}
let result = sum(1, 2);
alert( result ); // 3
La directive return peut être nâimporte où dans la fonction. Lorsque lâexécution le permet, la fonction sâarrête et la valeur est renvoyée au code appelant (affecté à result ci-dessus).
Il peut y avoir plusieurs occurrences de return dans une seule fonction. Par exemple :
function checkAge(age) {
if (age >= 18) {
return true;
} else {
return confirm('Do you have permission from your parents?');
}
}
let age = prompt('How old are you?', 18);
if ( checkAge(age) ) {
alert( 'Access granted' );
} else {
alert( 'Access denied' );
}
Il est possible dâutiliser return sans valeur. Cela entraîne la sortie immédiate de la fonction.
Par exemple :
function showMovie(age) {
if ( !checkAge(age) ) {
return;
}
alert( "Showing you the movie" ); // (*)
// ...
}
Dans le code ci-dessus, si checkAge(age) renvoie false, alors ShowMovie nâeffectuera pas lâalert.
return vide ou rien dedans retourne undefinedfunction doNothing() { /* vide */ }
alert( doNothing() === undefined ); // true
Un return vide est également identique à un return undefined :
function doNothing() {
return;
}
alert( doNothing() === undefined ); // true
return et la valeurPour une longue expression dans return, il pourrait être tentant de la mettre sur une ligne séparée, comme ceci :
return
(some + long + expression + or + whatever * f(a) + f(b))
Cela ne fonctionne pas, car JavaScript suppose un point-virgule après le return. Cela fonctionnera comme :
return;
(some + long + expression + or + whatever * f(a) + f(b))
Donc, cela devient effectivement un retour vide.
Si nous voulons que lâexpression renvoyée recouvre plusieurs lignes, nous devons la démarrer à la même ligne que return. Ou du moins mettre les parenthèses dâouverture comme suit :
return (
some + long + expression
+ or +
whatever * f(a) + f(b)
)
Et cela fonctionnera comme prévu.
Nommer une fonction
Les fonctions sont des actions. Donc, leur nom est généralement un verbe. Il convient de décrire brièvement, mais aussi précisément que possible, le rôle de la fonction. Pour quâune personne qui lit le code reçoive le bon indice.
Câest une pratique répandue de commencer une fonction avec un préfixe verbal qui décrit vaguement lâaction. Il doit exister un accord au sein de lâéquipe sur la signification des préfixes.
Par exemple, les fonctions qui commencent par "show" affichent généralement quelque chose.
Fonction commençant parâ¦
"getâ¦"â retourne une valeur,"calcâ¦"â calcule quelque chose,"createâ¦"â créer quelque chose,"checkâ¦"â vérifie quelque chose et retourne un booléen, etc.
Exemples de quelques noms :
showMessage(..) // affiche un message
getAge(..) // renvoie l'âge (l'obtient en quelque sorte)
calcSum(..) // calcule une somme et renvoie le résultat
createForm(..) // crée un formulaire (et le retourne généralement)
checkPermission(..) // vérifie une permission, retourne vrai/faux
Avec les préfixes en place, un coup dâÅil sur un nom de fonction permet de comprendre le type de travail effectué et le type de valeur renvoyé.
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, nous pouvons créer une troisième fonction qui appelle ces deux actions).
Quelques exemples de violation de cette règle :
getAgeâ serait mauvais si elle affichait unealertavec lââge (devrait seulement obtenir).createFormâ serait mauvais sâil modifiait le document en y ajoutant un formulaire (il ne devrait que le créer et le renvoyer).checkPermissionâ serait mauvais sâil affiche le message dâaccès accordé/refusé (doit uniquement effectuer la vérification et renvoyer le résultat).
Ces exemples supposent des significations communes de préfixes. Vous et votre équipe êtes libres de vous entendre sur dâautres sens, mais ils ne sont généralement pas très différents. 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 ayant le même préfixe doivent obéir aux règles. Et lâéquipe devrait partager ces connaissances.
Fonctions == Commentaires
Les fonctions doivent être courtes et faire exactement une seule chose. Si cette chose est conséquente, il vaut peut-être la peine de scinder la fonction en quelques fonctions plus petites. Parfois, suivre cette règle peut ne pas être aussi facile, mais câest définitivement une bonne pratique.
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. Chacune extrait les nombres premiers jusquâà n.
La première variante utilise un label :
function showPrimes(n) {
nextPrime: for (let i = 2; i < n; i++) {
for (let j = 2; j < i; j++) {
if (i % j == 0) continue nextPrime;
}
alert( i ); // un nombre premier
}
}
La deuxième variante utilise une fonction supplémentaire isPrime(n) pour tester la primalité :
function showPrimes(n) {
for (let i = 2; i < n; i++) {
if (!isPrime(i)) continue;
alert(i); // un nombre premier
}
}
function isPrime(n) {
for (let i = 2; i < n; i++) {
if ( n % i == 0) return false;
}
return true;
}
La deuxième variante est plus facile à comprendre, nâest-ce pas ? Au lieu du bloc de code, nous voyons le nom de lâaction (isPrime). Parfois, les gens se réfèrent à ce code comme étant auto-descriptif.
Des fonctions peuvent donc être créées même si nous nâavons pas lâintention de les réutiliser. Ils structurent le code et le rendent lisible.
Résumé
Une déclaration de fonction ressemble à ceci :
function name(parameters, delimited, by, comma) {
/* 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. 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, le résultat est
undefined.
Pour rendre le code propre 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 possède des paramètres, fonctionne avec eux et renvoie un résultat, plutôt quâune fonction qui ne comporte aucun paramètre, mais modifie des variables externes comme un effet secondaire.
Nommage de fonction :
- Un nom doit clairement décrire le rôle de la fonction. Lorsque nous voyons un appel de fonction dans le code, un bon nom nous donne instantanément une compréhension de ce quâelle fait et de ce quâelle retourne.
- Une fonction est une action, les noms de fonctions sont donc généralement verbaux.
- Il existe de nombreux préfixes de fonctions bien connus, tels que
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. Maintenant que nous avons couvert les bases, nous pouvons donc commencer à les créer et les utiliser. Mais ce nâest que le début du chemin. Nous allons y revenir plusieurs fois, en approfondissant leurs fonctionnalités avancées.
Commentaires
<code>, pour plusieurs lignes â enveloppez-les avec la balise<pre>, pour plus de 10 lignes - utilisez une sandbox (plnkr, jsbin, codepenâ¦)