Je continue la série sur javascript et ses fondamentaux. Dans cet article, j’aborde la question des fonctions.

Pré-requis

Le pré-requis n’est pas indispensable mais est conseillé: l’article sur les types fondamentaux en javascript.

Introduction

Je vais vous montrer les différentes façons de définir et exécuter une fonction. Les fonctions javascript étant des objets, les comportements sont différents de ceux que vous pouvez connaitre dans d’autres langages. Et il est important de comprendre ces modes de fonctionnement pour bien comprendre le langage javascript.

Définition d’une fonction en javascript

Une première manière de déclarer une fonction se fait en débutant par le mot clé function.

function maFonction(param1, param2) {
  let value;
  ....
  return value;
}

Deuxième méthode par le biais d’une fonction anonyme affectée à une variable. La fonction étant un objet, la variable stocke un pointeur vers cette fonction.

let maFonction = function(param1, param2) {
  let value;
  ....
  return value;
}

Même si les deux modes de déclaration sont quasi identiques, une petit subtilité subsiste: la première déclaration est hissée en début de code quelque soit le lieu de déclaration.

le code écrit par le développeur

le code interprété par javascript

maFonction();
function maFonction() {
 …..

}

function maFonction() {
 ….
}
maFonction();

Le code suivant génère une erreur, la définition de la fonction n’est pas hissée :

maFonction();
let maFonction = function() {
  ....
}

Une fonction peut être une valeur

Une fonction étant un objet, elle peut au même titre que tout autre objet être une valeur.

Dans l’exemple ci-dessous maFonction1 et maFonction2 pointent sur le même objet qui est une fonction, donc la même fonction et exécute donc le même code.

function maFonction1 = function() {
  ....
}
let maFonction2 = maFonction1;

Autre exemple, une fonction peut être un paramètre d’une autre fonction. La fonction de tri sort peut prendre en paramètre une fonction de tri.

// trier des entiers
let numbers = [1,5,8,4,7,10,2,6];
numbers.sort(function(first,second) {
  return first - second;
});
console.log(numbers); // affiche "[1,2,4,5,6,7,8,10]"

Sans fonction en paramètre, la fonction sort trie des chaines de caractères

let numbers = [1,5,8,4,7,10,2,6];
console.log(numbers); // affiche "[1,10,2,4,5,6,7,8]"
// le tableau d'entiers est converti en tableau de chaines de caractères lors du tri

Les paramètres d’une fonction

Un autre aspect des fonctions javascript est la possibilité de passer autant de paramètres que vous voulez lors de l’appel d’une fonction sans que cela ne génère d’erreur.
En fait, tous les paramètres d’une fonction sont stockées dans un tableau nommés arguments. Tout comme un objet Array, les valeurs sont référencées par des indices numériques, il peut comporter autant d’éléments que nécessaire et la propriété length renvoie le nombre d’éléments contenus. Attention, la fonction qui est un objet possède aussi une propriété length qui elle renvoie le nombre de paramètres attendus conformément à sa définition. Attention aussi au fait que arguments n’est pas un objet Array.

Surcharger une fonction

La plupart des langages objet supportent la surcharge : une méthode peut avoir de multiples signatures. Ces langages supportent plusieurs définitions d’une même méthode avec un nombre de paramètres différent. En javascript, ce n’est pas aussi simple: si vous définissez deux fois une même fonction, c’est la dernière définition qui fera foi. Ceci quelque soit la forme que vous utilisez pour la définir. Illustration :

function logMessage(message) {
  console.log(message);
}
function logMessage() {
  console.log("default log message");
}
logMessage("monMessage"); // affiche 'default log message'

Le seul moyen que vous ayez pour varier les comportements est d’utiliser le tableau de paramètres arguments. Vous pourriez par exemple tester l’absence de paramètres par le biais du test arguments.length === 0.

Les méthodes d’un objet

Comme mentionné dans l’article sur les types fondamentaux en javascript, ajouter ou supprimer des propriétés en javascript est chose facile, et lorsque qu’une propriété est une fonction, elle est alors une méthode de l’objet.

let person = {
  name : "Arthur",
  sayName : function() {
    console.log(person.name);
  }
}
person.sayName(); // affiche 'Arthur'

Remarquez que l’appel d’une méthode se fait directement depuis l’objet.

L’objet this

Dans l’exemple précédent, l’appel de la propriété name dans la fonction sayName a été fait avec l’objet person. Cela pose plusieurs problèmes, le premier étant que toute modification du nom de l’objet person va nécessiter de modifier tous les endroits où il est invoqué, et le second est le couplage (lien) fort induit, empêchant tout usage dans un autre objet de même type.

La solution est d’utiliser l’objet this qui est le contexte d’appel pour une fonction. Lorsque qu’une fonction attachée à une objet est appelée, le contexte d’appel est l’objet lui-même: this est l’objet lui-même.

let person = {
  name : "Arthur",
  sayName : function() {
    console.log(this.name);
  }
}
person.sayName(); // affiche 'Arthur'

Une fonction pouvant être appelée dans une multitude de contexte, il y a parfois besoin de spécifier ce contexte d’appel et donc this qui représente le contexte d’appel par le biais de la méthode call.

function maFonction(monParametre) {
  console.log(monParametre + " - " + this.monParametreObjet);
}
let monObjet1 = {
  monParametreObjet = "valeurParametreObjet1";
};
let monObjet2 = {
  monParametreObjet = "valeurParametreObjet2";
};
maFonction.call(monObjet1,"valeur monParametre Objet 1"); // affiche 'valeur monParametre Objet1 - valeurParametreObjet1'
maFonction.call(monObjet2,"valeur monParametre Objet 2"); // affiche 'valeur monParametre Objet2 - valeurParametreObjet2'

La méthode apply permet aussi de le faire: alors que call prend de multiples paramètres à partir du deuxième, apply n’en prend que deux, mais le second paramètre est un tableau de paramètres.

ECMAScript 5 a introduit la méthode bind qui, tout comme call et apply, prend en premier paramètre le contexte, mais ne fait aucun appel. La fonction bind crée une fonction qui encapsule dans une nouvelle fonction le contexte d’appel et l’appel.

function maFonction(monParametre) {
  console.log(monParametre + " - " + this.monParametreObjet);
}
let monObjet1 = {
  monParametreObjet = "valeurParametreObjet1";
};
let monObjet2 = {
  monParametreObjet = "valeurParametreObjet2";
};
let nouvelleFonction = maFonction.bind(monObjet1);
nouvelleFonction("parametre");  // affiche 'parametre- valeurParametreObjet1'
Tout a été à peu près dit sur les fonctions javascript, gardez bien tout cela à l’esprit, ça vous évitera des surprises ou encore des comportements de code incompréhensibles.

 

Si vous avez aimé cet article, partagez le.

 

Si vous constatez des coquilles, ou avez des remarques à faire ou encore souhaitez manifester votre satisfaction de ce tuto, n’hésitez pas les commentaires sont faits pour ça.