Pour les Jedis, JavaScript, épisode I : Au coeur des fonctions (partie 2)

Wassim Chegham
Oct 1, 2018 · 6 min read

Cet article fait partie de la série “Pour les Jedis, JavaScript” d’articles consacrés à JavaScript. Si ce n’est pas déjà fait, veuillez lire les épisodes précédents.

  1. Pour les Jedis, JavaScript, épisode I : Au cœur des Fonctions (1 et 2)
  2. Pour les Jedis, JavaScript, épisode II : L’attaque des Closures (1 et 2)
  3. Pour les Jedis, JavaScript, épisode III : La revanche des Prototypes (1 et 2)

Invocation en tant que fonction

Ce type d’invocation est sûrement le plus utilisé. En effet, si une fonction n’est pas invoquée en tant que méthode, constructeur ou via ou , alors nous sommes en présence d’invocation d’une fonction.

Cette invocation se produit lorsque la fonction est invoquée en utilisant les parenthèses et lorsque cette fonction n’est pas une propriété d’un objet. Voici un exemple plus parlant :

Lorsqu’il est invoqué de cette manière, le contexte d’invocation de ces fonctions est , le contexte globale en JavaScript.

Invocation en tant que méthode

Lorsqu’une fonction est une propriété d’un objet et que l’invocation se fait en appelant cette fonction, alors la fonction est invoquée en tant que méthode de cet objet. Pour illustrer cela, étudions cet exemple :

Invocation en tant que constructeur

Un constructeur est une simple fonction, il n’a vraiment rien de spécial. La seule différence réside dans la façon dont elle va être invoquée. Pour invoquer une fonction en tant que constructeur, nous le précédons par le mot-clé .

A noter que ES2015 a introduit la notion de Class en JavaScript, ce qui est simplement un sucre syntaxique autour des fonctions en tant que constructeurs.

Invoquer une fonction en tant que constructeur est un aspect très intéressant de JavaScript, car lorsqu’un constructeur est invoqué, plusieurs choses se produisent :

  • un nouvel objet vide est créé, le fameux paramètre ;
  • cet objet est passé au constructeur. Il devient donc le contexte d’invocation ;

En l’absence d’une instruction explicite dans le constructeur, cet objet est retourné par le constructeur. Prenons cet exemple :

Nous avons déclaré un constructeur , celui-ci déclare une propriété , qui est une méthode retournant le contexte (pour l’exemple).

Dans un premier temps, nous invoquons ce constructeur avec le mot-clé et nous avons bien un objet de type qui a été créé, et qui possède bien une méthode . Un petit test sur le contexte dans , nous prouve que c’est bien une instance de .

Dans l’exemple 2, nous avons essayé de démontrer qu’invoquer un constructeur en tant que fonction, sans le mot-clé , ne donne pas du tout le résultat attendu. En effet, invoquer en tant que fonction, exécute simplement le code de cette fonction, ce qui provoque la création de la propriété dans l’objet hôte — dans lequel a été invoquée. Cet objet représenté par dans est bien évidemment , puisque la fonction a été déclarée dans le contexte global de JavaScript.

“Invoquer un constructeur en tant que fonction est risqué.”

Jusque là, nous avons vu que le type d’invocation d’une fonction agit directement sur le contexte d’invocation, représenté par le paramètre implicite . Pour les méthodes c’est l’objet hôte ; pour les fonctions déclarées dans le contexte global c’est le ; et pour les constructeurs c’est l’instance du nouvel objet créé.

Maintenant, comment pouvons-nous faire si nous voulons forcer un contexte d’invocation particulier ? C’est bien grâce à et .

Invocation via apply() ou call()

JavaScript offre une méthode simple, pour invoquer une fonction et lui spécifier explicitement un contexte d’invocation. Nous pouvons réaliser cela grâce à deux méthodes proposées par toutes les fonctions : et .

Pourquoi voudrions-nous faire cela ? Prenons l’exemple d’une situation que nous rencontrons régulièrement en JavaScript : les actions — ou callbacks — des événements déjà abordés précédemment. Lorsque nous déclarons une fonction de callback sur un événement, celle-ci est invoquée lorsque l’événement en question est traité par le navigateur. Cette fonction de callback est invoquée avec le contexte de l’événement, c’est un comportement par défaut du navigateur.

Comme l’illustre le code ci-dessus, le contexte d’invocation de la fonction de callback — représenté par — est celui de ; la callback est une fonction déclarée dans le contexte globale. Elle a été invoquée en tant que fonction.

Voyons maintenant le même code mais cette fois-ci en utilisant la méthode .

En invoquant une fonction — ou méthode — avec , nous passons un premier paramètre qui représente le contexte d’invocation. Dans notre exemple, ce contexte est l’élément DOM qui nous intéresse. En plus du contexte d’invocation, nous avons aussi passé une liste de paramètre à la fonction .

Avec , c’est quasiment la même chose : nous passons également le contexte d’invocation en premier paramètre. Mais contrairement à , la méthode prend en second paramètre un tableau représentant la liste des arguments.

Voici un autre exemple plus intéressant :

Dans cet exemple, nous avons déclaré une fonction qui permet d’itérer sur une liste d’éléments. Cette fonction prend en second paramètre une fonction de callback qui sera invoquée pour chaque élément parcouru, avec le contexte de la liste (nous aurions pu spécifier un autre contexte), et nous donne en paramètre l’index de l’élément courant.

Quelle méthode utiliser ?

Cela dépend de votre cas d’usage, et plus précisément cela dépend de comment vous devez gérer vos paramètres. Si vous avez un ensemble de variables que vous devez passer en tant que paramètres, serait idéale. Mais si vous avez déjà votre liste de variables sous forme de tableau (par exemple, ), est plus appropriée. Prenons par exemple la méthode de JavaScript : cette méthode calcule le maximum d’une liste de valeur qu’elle prend en paramètre :

.

Supposons que vous voudriez calculer le maximum (ou le minimum) d’une suite de valeur dont vous ne connaissez pas la longueur :

Dans cet exemple, je viens de déclarer une fonction nommée qui calcule le maximum d’une suite de nombres passés en paramètre. S’il n’y a aucun paramètre, le résultat est zéro. Je me repose donc sur le paramètre implicites arguments pour réaliser cette vérification. Vous comprenez tout de suite qu’utiliser a tout son sens dans cet exemple. Veuillez noter également que j’ai passé en tant que contexte d’invocation à la méthode : je n’étais pas obligé d’en spécifier un, mais c’est plus sûr comme ça !

Un mot sur bind()

En JavaScript, il existe une autre façon de contrôler le contexte d’invocation d’une fonction. Contrairement à et , ce contrôle est fait au moment de la déclaration de la fonction, et non à l’invocation.

Ce contrôle est rendu possible grâce à la méthode permettant de transformer le contexte d’invocation d’une fonction. Jetons un œil à l’exemple suivant :

Nous avons déclaré un constructeur (ou Classe) . Ce constructeur possède une méthode , qui permet d’incrémenter un compteur . Ensuite, nous attachons un événement sur un élément DOM (disons, un bouton par exemple). A chaque clique nous souhaitons incrémenter le compteur de .

Dans un premier temps (cas #1), nous attachons la méthode en tant qu’action sur le click. Mais là, problème ! En effet, l’attribut n’est pas résolu ; tout simplement puisque le contexte d’invocation de n’est pas l’instance mais (rappelez vous l’exemple cité plus haut avec le ).

Pour résoudre ce problème, nous aurions pu passer par une fonction anonyme (cas #2) dans laquelle nous aurions invoqué la méthode . Mais pourquoi déclarer une fonction juste pour invoquer une autre ? Il y a plus simple, nous utilisons la méthode en précisant comme contexte d’invocation (cas #3). Mais rappelez-vous que n’invoque pas la fonction en question, elle modifie simplement son contexte d’invocation.

Voilà !

Dans ce premier épisode, nous avons étudié en détails un des aspects fascinant de JavaScript : JavaScript en tant que langage fonctionnel. J’espère qu’en comprenant comment les fonctions sont interprétées en interne par JavaScript, cela vous aidera à écrire un meilleur code JS, en passant d’un “simple” code qui “fait l’affaire” à un code digne d’un vrai Jedi que vous êtes dorénavant.

Voilà, nous avons atteint la fin de ce premier épisode ; rendez-vous pour le second épisode dans lequel nous allons tenter de percer le mystère des fermetures en JavaScript, connus sous le nom de Closures.

Que le JS soit avec vous…

Vous avez aimé cet article ? Ajoutez des claps et Suivez moi sur Medium et Twitter pour plus de contenu sur JavaScript et le Web 🎉

CodeShake

Learnings and insights from SFEIR community.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store