Fonctions et portée des fonctions
Baseline
Large disponibilité
*
Cette fonctionnalité est bien établie et fonctionne sur de nombreux appareils et versions de navigateurs. Elle est disponible sur tous les navigateurs depuis juillet 2015.
* Certaines parties de cette fonctionnalité peuvent bénéficier de prise en charge variables.
De manière générale, une fonction est un « sous-programme » qui peut être appelé par du code extérieur à la fonction (ou du code interne dans le cas d'une récursion). Comme le programme, une fonction est composée d'une suite d'instructions qui forment le corps de la fonction. Il est parfois possible de passer des valeurs à une fonction et une fonction peut éventuellement retourner (ou renvoyer) une valeur.
En JavaScript, les fonctions sont des objets de première classe. Cela signifie qu'elles peuvent être manipulées et échangées, qu'elles peuvent avoir des propriétés et des méthodes, comme tous les autres objets JavaScript. Les fonctions sont des objets Function.
Pour plus d'informations et d'exemples, on pourra également consulter le chapitre du Guide JavaScript sur les fonctions.
Description
Toute fonction JavaScript est en fait un objet Function. Voir la page Function pour des informations sur les propriétés et les méthodes de ces objets.
Afin de renvoyer une valeur, la fonction doit comporter une instruction return qui définit la valeur à renvoyer (sauf dans le cas d'un constructeur qui a été appelé avec le mot-clé Operators/new). Une fonction qui ne renvoie pas de valeur retourne undefined.
Les paramètres donnés lors de l'appel d'une fonction sont appelés les arguments de la fonction. Les arguments sont passés par valeur (by value en anglais). Si la fonction modifie la valeur d'un argument, ce changement ne se répercute pas en dehors de la fonction. Il existe cependant les références d'objets qui sont aussi des valeurs mais qui possèdent la particularité suivante : si la fonction modifie les propriété de l'objet de la référence, ce(s) changement(s) seront perceptibles en dehors de la fonction. Prenons l'exemple suivant :
/* Déclaration de la fonction 'maFonction' */
function maFonction(monObjet) {
monObjet.marque = "Toyota";
}
/*
* Déclaration de la variable 'mavoiture';
* création et initialisation d'un nouvel objet;
* assigner une référence à 'mavoiture'
*/
var mavoiture = {
marque: "Honda",
modele: "Accord",
annee: 1998,
};
/* Affiche 'Honda' */
console.log(mavoiture.marque);
/* Passer la référence de l'objet à la fonction */
maFonction(mavoiture);
/*
* Affiche 'Toyota' pour valeur de la propriété 'marque'
* de l'objet. C'est ce que la fonction a changé.
*/
console.log(mavoiture.marque);
Le mot-clé this ne fait pas référence à la fonction en cours d'exécution. Il faut donc faire référence aux objets Function par leurs noms, et ce même au sein du corps de la fonction.
Définir des fonctions
Il y a plusieurs façons de définir des fonctions
Déclarer une fonction (l'instruction function)
Il existe une syntaxe spécifique pour la déclaration des fonctions (vous pouvez consulter la page de l'instruction function pour plus de détails) :
function nom([param[, param[, ... param]]]) {
instructions
}
nom-
Le nom de la fonction.
param-
Le nom d'un argument à passer à la fonction (une fonction pouvant avoir jusqu'à 255 arguments).
instructions-
Les instructions qui forment le corps de la fonction.
Utiliser une expression de fonction (l'expression function)
L'expression d'une fonction se fait d'une façon similaire à la déclaration (veuillez consulter la page de l'expression function pour plus d'informations) :
function [nom]([param] [, param] [..., param]) {
instructions
}
nom-
Le nom de la fonction. Il est facultatif, auquel cas la fonction devient une fonction anonyme.
param-
Le nom d'un argument à passer à la fonction.
instructions-
Les instructions qui forment le corps de la fonction.
Voici un exemple d'expression de fonction anonyme (il n'y a pas de nom utilisé) :
var maFonction = function () {
/* instructions */
};
Il est également possible de fournir un nom lors de la définition afin de créer une expression de fonction nommée :
var maFonction = function fonctionNommée() {
/* instructions */
};
L'un des bénéfices d'utiliser une expression de fonction nommée est que son nom sera utilisé dans la pile d'appel lors qu'on aura une erreur. Avec le nom de la fonction, il sera plus facile de repérer l'origine de l'erreur.
Comme on peut le voir, ces deux derniers exemples ne commencent pas avec le mot-clé function. Les instructions qui déclarent des fonctions mais qui ne commencent pas avec function sont des expressions de fonction.
Lorsque les fonctions sont utilisées une unique fois, on peut utiliser une « expression de fonction immédiatement invoquée » (ou plus généralement appelée IIFE pour Immediately Invokable Function Expression en anglais).
(function () {
/* instruction */
})();
Les IIFE sont des expressions de fonction appelées dès que la fonction est déclarée.
Utiliser une déclaration de fonction génératrice (l'instruction function*)
Il existe une syntaxe spéciale pour déclarer des générateurs (voir la page sur l'instruction function* pour plus de détails) :
function* nom([param[, param[, ... param]]]) {
instructions
}
nom-
Le nom de la fonction.
param-
Le nom d'un argument à passer à la fonction.
instructions-
Les instructions qui forment le corps de la fonction.
Utiliser une expression de générateur (l'expression function*)
Une expression de générateur est similaire à une déclaration de fonction génératrice et possède presque la même syntaxe (pour plus de détails, consulter la page sur l'expression function*) :
function* [nom]([param[, param[, ... param]]]) {
instructions
}
nom-
Le nom de la fonction. Ce paramètre peut être omis, auquel cas la fonction sera une fonction anonyme.
param-
Le nom d'un argument à passer à la fonction.
instructions-
Les instructions qui composent le corps de la fonction.
Utiliser une expression de fonction fléchée (=>)
Une expression de fonction fléchée possède une syntaxe plus courte et est liée, de façon lexicale, à sa valeur (voir la page sur les fonctions fléchées pour plus de détails) :
([param[, param]]) => {
instructions
}
param => expression
param-
Le nom d'un argument. S'il n'y a pas d'arguments, cela doit être indiqué par
(). S'il y a un seul argument, les parenthèses ne sont pas obligatoires (par exemple :toto => 1). instructionsouexpression-
S'il y a plusieurs instructions, elles doivent être encadrées par des accolades. Une expression unique ne doit pas obligatoirement être entourée d'accolades. L'expression est également la valeur de retour implicite de la fonction.
Le constructeur Function
Note :
L'utilisation du constructeur Function afin de créer des fonction n'est pas recommandée. En effet, il utilise une chaîne pour former le corps de la fonction et cela peut empêcher certaines optimisations du moteur JavaScript ainsi que provoquer d'autres problèmes.
Comme tous les autres objets, les objets Function peuvent être créés grâce à l'opérateur new :
new Function(arg1, arg2, ...argN, corpsDeLaFonction);
arg1, arg2, ... argN-
Plusieurs (zéro ou plus) noms qui seront utilisés par la fonction comme noms d'arguments formels. Chaque nom doit être une chaîne de caractères valide au sens d'un identifiant JavaScript ou alors être une liste de telles chaînes séparées par des virgules. On aura les exemples suivants : "
x", "laValeur", ou "a,b". corpsDeLaFonction-
Une chaîne de caractères contenant les instructions JavaScript définissant la fonction.
L'invocation du constructeur Function en tant que fonction (sans utiliser l'opérateur new) a le même effet que son invocation en tant que constructeur.
Le constructeur GeneratorFunction
Note :
GeneratorFunction n'est pas un objet global mais pourrait être obtenu à partir de l'instance de la fonction génératrice (voir la page GeneratorFunction pour plus de détails).
Note :
Le constructeur GeneratorFunction ne doit pas être utilisé pour créer des fonctions. En effet, il utilise une chaîne pour former le corps de la fonction et cela peut empêcher certaines optimisations du moteur JavaScript ainsi que provoquer d'autres problèmes.
Comme pour tous les autres objets, les objets GeneratorFunction peuvent être créés grâce à l'opérateur new :
new GeneratorFunction(arg1, arg2, ...argN, corpsFonction);
arg1, arg2, ... argN-
Plusieurs (zéro ou plus) noms qui seront utilisés par la fonction comme noms d'arguments formels. Chaque nom doit être une chaîne de caractères valide au sens d'un identifiant JavaScript ou alors être une liste de telles chaînes séparées par des virgules. On aura les exemples suivants : "
x", "theValue", ou "a,b". corpsFonction-
Une chaîne de caractères contenant les instructions JavaScript définissant la fonction.
Les paramètres d'une fonction
>Les paramètres par défaut
Les paramètres par défaut permettent aux paramètres déclarés d'une fonction de pouvoir être initialisés avec des valeurs par défaut s'ils ne sont pas fournis à la fonction ou s'ils valent undefined. Pour plus de détails, voir la page de la référence sur les paramètres par défaut.
Les paramètres du reste
Cette syntaxe permet de représenter un nombre indéfini d'arguments sous forme d'un tableau. Pour plus de détails, voir la page sur les paramètres du reste.
L'objet arguments
Il est possible de faire référence aux arguments d'une fonction au sein de cette fonction en utilisant l'objet arguments. Consulter la page arguments pour plus d'informations.
arguments: Un objet semblable à un tableau qui contient les arguments passés à la fonction qui est exécutée.arguments.callee: La fonction en cours d'exécution.arguments.caller: La fonction qui a appelé la fonction courante.arguments.length: Le nombre d'arguments passés à la fonction.
Récursion
Une fonction peut faire référence à elle-même et s'appeler elle-même. Il y a trois façons pour qu'une fonction fasse appel à elle-même :
- le nom de la fonction
arguments.callee- une variable interne faisant référence à la fonction
Avec l'exemple suivant :
var truc = function toto() {
// instructions
};
Ce qui suit sera équivalent au sein de la fonction :
toto()arguments.callee()truc()
Une fonction qui s'appelle elle-même est appelée une fonction récursive. D'une certaine manière, une récursion est semblable à une boucle. Une récursion et une boucle exécutent le même code plusieurs fois et s'appuient sur une condition (afin d'éviter une boucle infinie, ou plutôt une récursion infinie ici). Ainsi la boucle suivante :
var x = 0;
// "x < 10" est la condition de la boucle
while (x < 10) {
// faire des choses
x++;
}
peut être convertie en une fonction récursive et un appel à cette fonction :
function boucle(x) {
// "x >= 10" est la condition de sortie
// (et équivaut à "!(x < 10)")
if (x >= 10) return;
// faire des choses
boucle(x + 1); // l'appel récursif
}
boucle(0);
Cependant, certains algorithmes ne peuvent pas être traduits sous forme de boucles itératives. Ainsi, obtenir tous les nœuds d'un arbre (par exemple le DOM), est beaucoup plus facile à faire de manière récursive.
function parcoursArbre(noeud) {
if (noeud == null)
//
return;
// faire quelque chose avec le noeud
for (var i = 0; i < noeud.childNodes.length; i++) {
parcoursArbre(noeud.childNodes[i]);
}
}
Par rapport à la fonction boucle, chaque appel récursif enchaîne ici plusieurs appels récursifs successifs.
Il est théoriquement possible de convertir tout algorithme récursif en un algorithme non-récursif. Cependant, la logique du problème est souvent beaucoup plus complexe et l'on doit faire recours à une pile pour le résoudre. Mais la récursion n'est en fait rien d'autre que l'utilisation d'une pile : la pile de la fonction.
La comportement de la récursion en tant que pile peut être observée avec cet exemple :
function truc(i) {
if (i < 0) return;
console.log("début :" + i);
truc(i - 1);
console.log("fin :" + i);
}
truc(3);
Elle produira le résultat suivant :
début :3 début :2 début :1 début :0 fin :0 fin :1 fin :2 fin :3