Fonctions

Les fonctions font partie des briques fondamentales qui composent JavaScript. Une fonction est une procédure JavaScript, un ensemble d'instructions effectuant une tâche ou calculant une valeur. Afin d'utiliser une fonction, il est nécessaire de l'avoir auparavant définie au sein de la portée dans laquelle on souhaite l'appeler.

Définir des fonctions

Une définition de fonction (autrement appelée déclaration de fonction) est construite avec le mot-clé function, suivi par :

  • Le nom de la fonction,
  • Une liste d'arguments à passer à la fonction, entre parenthèses et séparés par des virgules,
  • Les instructions JavaScript définissant la fonction, entre accolades, { }.

Le code suivant, par exemple, définit une fonction intitulée carré:

function carré(nombre) {
  return nombre * nombre;
}

La fonction carré prend un seul argument, appelé nombre. La fonction est composée d'une seule instruction qui renvoie l'argument de la fonction (nombre) multiplié par lui-même. L'instruction return spécifie la valeur qui est renvoyée par la fonction.

return nombre * nombre;

Les paramètres primitifs (comme les nombres) sont passés à la fonction par valeur. La valeur est passée à la fonction mais si cette dernière change la valeur du paramètre, cela n'aura pas d'impact au niveau global ou au niveau de ce qui a appelé la fonction.

Si l'argument passé à la fonction est un objet (une valeur non-primitive, comme un objet Array ou un objet  défini par l'utilisateur), et que la fonction change les propriétés de cet objet, ces changements seront visibles en dehors de la fonction. Par exemple :

function maFonction(monObjet) {
  monObjet.fabricant = "Toyota";
}

var mavoiture = {fabricant: "Honda", modèle: "Accord", année: 1998},
    x,
    y;

x = mavoiture.fabricant;     // x aura la valeur "Honda"

maFonction(mavoiture);
y = mavoiture.fabricant;     // y aura la valeur "Toyota"
                    // (la propriété fabricant a été modifiée par la fonction)

Assigner un nouvel objet au paramètre n'aura pas d'effet en dehors de la fonction car cela revient à changer la valeur du paramètre plutôt que la valeur d'une propriétés de l'objet. Par exemple :

function maFonction(monObjet) {
  monObjet = {fabricant: "Ford", modèle: "Focus", année: 2006};
}

var mavoiture = {fabricant: "Honda", modèle: "Accord", année: 1998},
    x,
    y;

x = mavoiture.fabricant;     // x reçoit la valeur "Honda"

maFonction(mavoiture);
y = mavoiture.fabricant;     // y reçoit la valeur "Honda" 

Dans le premier exemple, l'objet mavoiture était passé à la fonction maFonction qui le modifiait. Dans le second exemple, la fonction n'a pas modifié l'objet qui avait été passé en argument, elle a créé une nouvelle variable locale, possédant le même nom que l'objet global passé en argument : il n'y a donc pas de modifications sur cet objet global.

Syntaxiquement, la déclaration de fonction utilisée ci-dessus est une instruction. On peut également créer une fonction grâce à une expression de fonction. De telles fonctions peuvent être anonymes (n'être pas nommées). La fonction carré aurait pu être définie de la façon suivante :

var carré = function(nombre) {return nombre * nombre};
var x = carré(4) //x reçoit la valeur 16

Cependant, un nom peut être utilisé dans une expression de fonction, ce afin de l'utiliser dans la fonction (récursivité) ou afin de l'identifier dans les appels tracés par un éventuel débogueur :

var factorielle = function fac(n) {return n<2 ? 1 : n*fac(n-1)};

print(factorielle(3));

Les expressions de fonction sont pratiques lorsqu'il s'agit de passer une fonction comme argument d'une autre fonction. Dans l'exemple qui suit, la fonction map est définie et appelée avec une fonction anonyme comme premier argument :

function map(f,a) {
  var resultat = [], // Créer un nouveau tableau Array
      i;
  for (i = 0; i != a.length; i++)
    resultat[i] = f(a[i]);
  return resultat;
}

Le code suivant :

map(function(x) {return x * x * x}, [0, 1, 2, 5, 10]);

renverra le tableau [0, 1, 8, 125, 1000].

En JavaScript, une fonction peut être définie selon une condition. Le fragment de code qui suit définit une fonction seulement si num vaut 0 :

var maFonction;
if (num == 0){
  maFonction = function(monObjet) {
    monObject.fabricant = "Toyota"
  }
}

Une autre façon pour définir des fonctions est d'utiliser le constructeur de l'objet Function afin de créer des fonctions à partir d'une chaîne lors de l'exécution, de la même façon que eval().

Une méthode est une fonction étant une propriété d'un objet. Vous trouverez plus de détails sur ces éléments dans le chapitre suivant du guide : Manipuler les objets.

Appeler des fonctions

La seule définition d'une fonction ne permet pas d'exécuter la fonction. Cela permet de lui donner un nom et de définir ce qui doit être fait lorsque la fonction est appelée. Appeler la fonction permet d'effectuer les actions des instructions avec les paramètres indiqués. Par exemple, si on définit la fonction carré, on peut l'appeler de la façon suivante :

square(5);

Cette instruction appellera la fonction avec un argument valant 5. La fonction exécute ses instructions et renvoie la valeur 25.

Les fonctions doivent appartenir à la portée dans laquelle elles sont appelées. En revanche, la déclaration d'une fonction peut être faite après l'appel :

print(carré(5));
/* ... */
function carré(n){return n*n} 

La portée d'une fonction est la fonction dans laquelle elle est déclarée ou le programme entier si elle est déclarée au niveau le plus haut. Cela ne fonctionne que si la définition de la fonction utilise la syntaxe précédente (function nomFonction(){}). Le code ci-dessous ne fonctionnera pas :

print(carré(5));
carré = function (n) {
  return n * n;
}

Les arguments d'une fonction ne sont pas limités aux chaînes de caractères et aux nombres. Il est possible de passer des objets. La fonction show_props (définie dans Manipuler les objets) est un exemple de fonction utilisant un argument qui est un objet.

Un fonction peut être récursive, c'est-à-dire qu'elle peut s'appeler elle-même. Voici la fonction qui calcule récursivement la factorielle d'un nombre :

function factorielle(n){
  if ((n == 0) || (n == 1))
    return 1;
  else
    return (n * factorielle(n - 1));
}

On peut ensuite calculer les factorielles des nombres 1 à 5 :

var a, b, c, d, e;
a = factorielle(1); // a reçoit la valeur 1
b = factorielle(2); // b reçoit la valeur 2
c = factorielle(3); // c reçoit la valeur 6
d = factorielle(4); // d reçoit la valeur 24
e = factorielle(5); // e reçoit la valeur 120

Il existe d'autres façons d'appeler des fonctions. Il existe souvent des cas où une fonction doit être appelée dynamiquement, où le nombre d'arguments peut varier, où le contexte de l'appel d'une fonction doit être créé en fonction d'un objet déterminé lors de l'exécution. Les fonctions sont des objets, en tant que tels, elles possèdent des méthodes. L'une d'entre elles, apply() peut être utilisée pour réaliser le dernier cas de figure (exécution d'une fonction avec un objet déterminé à l'exécution).

Portée d'une fonction

On ne peut pas accéder aux variables définies dans une fonction en dehors de cette fonction : ces variables n'existent que dans la portée de la fonction. En revanche, une fonction peut accéder aux différentes variables et fonctions qui appartiennent à la portée dans laquelle elle est définie. Une fonction définie dans une autre fonction peut également accéder à toutes les variables de la fonction « parente » et à toute autre variable accessible depuis la fonction « parente ».

// Les variables suivantes sont globales 
var num1 = 20,
    num2 = 3,
    nom = "Licorne";

// Cette fonction est définie dans la portée globale
function multiplier() {
  return num1 * num2;
}

multiplier(); // Renvoie 60

// Un exemple de fonction imbriquée
function getScore () {
  var num1 = 2,
      num2 = 3;
  
  function ajoute() {
    return nom + " a marqué " + (num1 + num2);
  }
  
  return ajoute();
}

getScore(); // Renvoie "Licorne a marqué 5"

Closures (Fermetures)

Les closures (fermetures) font parties des fonctionnalités les plus puissantes de JavaScript. JavaScript permet de définir des fonctions imbriquées et offre aux fonctions imbriquées l'accès aux variables et fonctions contenues dans la fonction parente (et toutes les autres variables et fonctions auxquelles cette fonction parente a accès). En revanche, la fonction parente n'a pas accès aux variables et aux fonctions définies dans la fonction imbriquée. Cela fournit une certaine sécurité quant au contenu de cette fonction imbriquée. L'accès vers les variables et fonctions définies au niveau de la fonction parente signifie également que ces variables et fonctions « vivront » plus longtemps que la fonction parente si la fonction imbriquée « vit » plus longtemps. On obtient une closure (fermeture) lorsque la fonction imbriquée est rendue disponible pour une portée en dehors de celle de la fonction parente.

var animal = function(nom) {       // La fonction parente définit une variable "nom"
      var getNom = function() {
        return nom;                // La fonction imbriquée accède à la variable "nom"
      }

      return getNom;               // On renvoie la fonction interne pour l'exposer aux portées extérieures
    },
    monAnimal = animal("Vivie");
    
monAnimal();                            // Renvoie "Vivie"

L'exemple précédent montre une utilisation simple des closures, on peut également obtenir des fonctionnalités plus complexes comme le renvoi d'un objet, par la fonction parente, contenant des méthodes de manipulation des variables internes.

var createPet = function(name) {
  var sex;
  
  return {
    setName: function(newName) {
      name = newName;
    },
    
    getName: function() {
      return name;
    },
    
    getSex: function() {
      return sex;
    },
    
    setSex: function(newSex) {
      if(typeof newSex == "string" && (newSex.toLowerCase() == "male" || newSex.toLowerCase() == "female")) {
        sex = newSex;
      }
    }
  }
}

var pet = createPet("Vivie");
pet.getName();                  // Vivie

pet.setName("Oliver");
pet.setSex("male");
pet.getSex();                   // male
pet.getName();                  // Oliver

Dans l'exemple qui précède, les fonctions imbriquées peuvent accéder à la variable name de la fonction parente et il n'existe pas de façon d'accéder aux variables internes sauf si on utilise les fonctions imbriquées. Les variables internes fonctionnent comme des coffres-forts pour les fonctions imbriquées. Elles maintiennent des données, de façon « sécurisée » et continue, utilisées par les fonctions imbriquées. Dans l'absolu, il n'est pas nécessaire que les fonctions soient nommées ou assignées à une variable.

var getCode = (function(){
  var codeSec = "0]Eal(eh&2";    // Un code à ne pas modifier depuis l'extérieur...
  
  return function () {
    return codeSec;
  };
})();

getCode();    // Renvoie le code secret

Il faut cependant faire attention à quelques éléments en ce qui concernent les closures. Si une fonction interne définit une variable avec le même nom qu'une autre variable de la portée parente, alors on ne peut plus faire référence à la variable de la portée externe.

var creerAnimal = function(nom) {  // La fonction parente définit une variable "nom"
  return {
    setNom: function(nom) {    // La fonction imbriquée définit également une variable "nom"
      nom = nom;               // ??? Comment accéder au "nom" défini  dans la fonction parente ???
    }
  }
}

La variable this est très délicate à manier également. En effet, this dépend entièrement de l'endroit où la fonction a été appelée (contexte) plutôt que l'endroit où elle a été définie. Un très bon article (en anglais) peut être trouvé ici.

Utiliser l'objet arguments

Les arguments d'une fonction sont maintenues dans un objet ressemblant à un tableau. Au sein d'une fonction, il est possible de faire référence aux arguments qui ont été passés en utilisant :

arguments[i]

i est le nombre ordinal de l'argument, la numérotation commençant à zéro. Pour obtenir le premier argument passé à la fonction, on pourra par exemple utiliser arguments[0]. Le nombre d'arguments est indiqué via arguments.length.

En utilisant l'objet arguments, il est possible d'appeler une fonction avec plus d'arguments que ceux utilisés dans la déclaration formelle de la fonction. Ceci peut s'avérer pratique s'il est impossible de connaître à l'avance le nombre de paramètres passés à la fonction. On peut alors utiliser arguments.length pour déterminer le nombre d'arguments qui ont réellement été passés puis accéder à chacun d'entre eux grâce à l'objet arguments.

Par exemple, si on souhaite implémenter une fonction concaténant plusieurs chaînes de caractètres. Le seul argument « formel » de la fonction est la chaîne de caractères utilisée comme séparateur des éléments à concaténer. Voici une façon d'implémenter cette fonction :

function maConcatenation(separateur) {
   var resultat = "", // on initialise la liste
       i;
   // on boucle sur les arguments
   for (i = 1; i < arguments.length; i++) {
      resultat += arguments[i] + separateur;
   }
   return resultat;
}

Il est possible d'utiliser autant d'arguments que possible avec cette fonction. Elle renverra une liste sous forme d'une chaîne de caractères :

// renvoie "rouge, orange, bleu, "
maConcatenation(", ", "rouge", "orange", "bleu");

// renvoie "éléphant; girafe; lion; singe; "
maConcatenation("; ", "elephant", "girafe", "lion", "singe");

// returns "estragon. basilic. origan. "
maConcatenation(". ", "estragon", "basilic", "origan");

Attention : cet objet arguments est proche d'un tableau en termes de structures mais ce n'est pas un objet Array. En effet, il dispose d'un accès par indice (arguments[i]) et d'une propriété length, cependant il ne possède pas les méthodes de manipulation d'un objet Array.

Voir plus de détails sur l'objet Function décrit dans la référence JavaScript.

Fonctions pré-définies

JavaScript possède plusieurs fonctions pré-définies. Les sections qui suivent décrivent brièvement ces fonctions. Vous pouvez consulter la référence JavaScript pour de plus amples informations.

Fonction eval

La fonction eval évalue une chaîne de caractères comme étant du code JavaScript, sans utiliser de référence vers un objet en particulier. Cette fonction s'utilise avec la syntaxe suivante :

eval(expr);

expr représente la chaîne de caractères qui doit être évaluée.

Si la chaîne de caractères représente une expression, eval évalue l'expression. Si l'argument représente plusieurs instructions JavaScript, eval exécutera les instructions. La portée du code contenu dans l'argument de la fonction eval est la même que celle où se situe la fonction. eval ne doit pas être appeler pour évaluer une expression arithmétique car cela est fait automatiquement.

Fonction isFinite

La fonction isFinite évalue un argument afin de déterminer si celui-ci est un nombre fini ou non. La syntaxe de cette fonction est :

isFinite(nombre);

nombre est le nombre qui doit être évalué.

Si l'argument vaut  NaN ou l'infini (positif ou négatif), la fonction renverra false, dans les autres cas, elle renverra true.

Le code qui suit vérifie si le code client est un nombre fini :

if(isFinite(codeClient)){
   /* effectuer différentes étapes */
}

Fonction isNaN

La fonction isNaN évalue un argument afin de déterminer s'il n'est pas un nombre  ("NaN" pour not a number). La syntaxex de cette fonction est :

isNaN(testValeur);

testValeur est la valeur à évaluer.

Les fonctions parseFloat et parseInt renvoient NaN lorsqu'elles évaluent une valeur qui n'est pas un nombre. isNaN renvoie true si l'argument vaut NaN, et false sinon.

Le code qui suit évalue nombreFlottant afin de déterminer si c'est un nombre pour appeler la procédure appropriée :

var nombreFlottant = parseFloat(toFloat);

if (isNaN(nombreFlottant)) {
   nonFlottant();
} else {
   estFlottant();
}

Fonctions parseInt et parseFloat

Ces deux fonctions d'analyse et de conversion, parseInt et parseFloat, renvoient une valeur numérique à partir d'une chaîne de caractères fournie en argument.

La fonction parseFloat s'utilise avec la syntaxe suivante :

parseFloat(str);

parseFloat analyse et convertit, si possible, la chaîne str en un nombre décimal. Si elle analyse un caractère qui n'est pas un signe (+ ou -), un chiffre (0-9), un point ou un exposant : elle renvoie la valeur analysée jusqu'à ce caractère et ignore les caractères suivants. Si le premier caractère ne peut pas être converti en un nombre, la fonction renvoie NaN (not a number : n'est pas un nombre ).

La fonction parseInt s'utilise avec la syntaxe suivante :

parseInt(str [, base]);

parseInt analyse son premier argument, la chaîne str, et renvoie, si possible, un entier dans la base base spécifiée, qui est donnée dans le second argument (optionnel). Ainsi, une base 10 sera utilisée pour convertir le premier argument en un nombre décimal, huit pour le convertir en nombre octal et seize pour le convertir en un nombre hexadécimal... Lorsqu'on utilise des bases supérieures à 10, les lettres de l'alphabet sont utilisées pour désigner les chiffres strictement supérieurs à 9. Les nombres hexadécimaux utilisent les lettres A à F à cet effet.

Si la fonction parseInt trouve un caractère qui n'est pas un chiffre dans la base donnée, elle ignore ce caractère et les caracètres suivants : elle renvoie la valeur de l'entier analysé jusqu'avant ce caractère. Si le premier caractère ne peut être converti en un nombre de la base donnée, elle renverra NaN. La fonction parseInt tronque la chaîne de caractères en valeurs entières.

Les fonctions Number et String

Les fonctions Number et String permettent de convertir un objet en un nombre ou en une chaîne de caractère. Ces fonctions s'utilisent avec la syntaxe suivante :

var objRef;
objRef = Number(objRef);
objRef = String(objRef);

où la variable objRef est une référence vers un objet. Number utilise la méthode valueOf() de l'objet alors que String utilise la méthode toString() de l'objet.

L'exemple qui suit permet de convertir un objet Date en un texte lisible :

var D = new Date(430054663215),
    x;
x = String(D); // x vaut "Thu Aug 18 04:37:43 GMT-0700 (Pacific Daylight Time) 1983"

L'exemple suivant permet de convertir un objet String en un objet Number.

var str = "12",
    num;
num = Number(str);

Pour le vérifier, vous pouvez utiliser la méthode DOM write() et l'opérateur JavaScript typeof.

var str = "12",
    num;
document.write(typeof str);
document.write("<br/>");
num = Number(str);
document.write(typeof num);

Fonctions escape et unescape (rendues obsolètes dans les versions supérieures à JavaScript 1.5)

Les fonctions escape et unescape ne fonctionnent pas correctement pour les caractères non-ASCII et ont donc été déclarées obsolètes. A partir de JavaScript 1.5, il est conseillé d'utiliser encodeURI, decodeURI, encodeURIComponent, et decodeURIComponent.

Les fonctions escape et unescape permettent d'encoder et de décoder des chaînes de caractères. La fonction escape renvoie un code hexadécimal de l'argument appartenant au jeu de caractères ISO Latin. La fonction unescape renvoie la chaîne de caractères ASCII de la valeur hexadécimale fournie en argument.

Ces fonctions s'utilisent avec la syntaxe suivante :

escape(string);
unescape(string);

Ces fonctions sont principalement utilisées côté serveur afin d'encoder et de décoder des paires noms-valeurs contenues dans des URL.

Document Tags and Contributors

Étiquettes :
Contributors to this page: Goofy, SphinxKnight
Dernière mise à jour par : SphinxKnight,