JavaScript est l’un de ces langages qui possède un mot-clé dédié pour définir des fonctions : le mot-clé function. Vous l’avez probablement déjà vu si vous avez déjà ouvert un fichier JavaScript dans les dernières années, mais nous allons voir aujourd’hui que ce n’est pas la seule façon de définir des fonctions en JavaScript !

Cet article s’intéressera donc aux différentes façons de déclarer des fonctions, et expliquera brièvement les différences entre ces façons.

Commençons par les fonctions traditionnelles. Si vous avec plus d’expérience avec les langages semblables au C, comme le C# ou le Java, vous écrivez probablement vos fonctions de cette façon, en général :

En passant au JavaScript, la syntaxe avec le mot-clé function n’est pas choquante :

Petite note si vous en êtes à vos premiers contacts avec JavaScript : certaines syntaxes ou possibilités vous seront peut-être surprenantes, et je ne prendrai pas la peine de tout expliquer. Au minimum, il vous faut savoir que JavaScript est un langage typé dynamiquement et sans annotation de types. C’est pourquoi, dans l’exemple plus haut, les paramètres a et b et la fonction multiply on ne retrouve aucune référence de type.

Je pense que vous pouvez voir pourquoi il est très facile de convertir des fonctions de langages semblables au C vers la syntaxe en JavaScript. En simplifiant un peu, une fonction est définie dans ces autres langages comme un symbole entouré d’un type de retour et de ses paramètres. En JavaScript, il suffit d’enlever les annotations de types et de remplacer le type de retour par le mot-clé function, et le tour est joué !

Cela dit, cette fonction est définie comme déclaration, ce qui veut dire que cette notation ne peut être utilisée que dans ce cadre. Puisque JavaScript s’inspire beaucoup de langages fonctionnels, cela en ferait une façon très limitée d’utiliser des fonctions, et pour cette raison, on retrouve, avec le même mot-clé, une autre forme pour les fonctions : les expressions.

Avoir accès à des fonctions comme expressions ouvre la porte à de nombreuses possibilités ! D’ailleurs, cette utilisation du mot-clé est très similaire à celle de delegate, en C#.

C’est donc très facile et simple de créer une fonction qui sera appelée par une autre fonction, comme dans notre appel à reduce, sur notre tableau.

L’aspect le plus important des fonctions comme expressions est le fait de pouvoir les assigner à des symboles. Il est toujours possible de nommer ces fonctions, mais de manière indirecte, c’est-à-dire en nommant le symbole qui va contenir une référence vers la fonction, plutôt que de nommer la fonction elle-même.

Si vous avez l’habitude de muter la valeur de vos variables, les fonctions comme expressions vous permettent par exemple de remplacer le contenu de votre symbole selon un ensemble de conditions. Par exemple, vous pourriez changer la fonction de validation contenue dans votre variable selon le type de données à valider.

Si vous préférez plutôt un style fonctionnel, et évitez donc de muter vos valeurs, cela vous permet de créer facilement des fonctions à l’intérieur de votre fonction, afin potentiellement de les envoyer à d’autres fonctions !

Comme vous pouvez le voir, c’est très pratique, mais la syntaxe devient vite lourde. En effet, la syntaxe traditionnelle vient avec pas mal de bruit, notamment ses accolades et le mot-clé return.

Depuis la version ES2015 de JavaScript, il existe cependant une nouvelle façon de déclarer des fonctions comme expressions, et il s’agit des fonctions fléchées. Voici à quoi ressemble l’exemple de code précédent écrit avec cette notation :

La syntaxe est donc plutôt simple : d’un côté, vous avez les paramètres de la fonction (on peut omettre les parenthèses, d’ailleurs, s’il n’y a qu’un seul paramètre), vous avez ensuite la « flèche » (les signes « égal » et « plus grand que », =>), et enfin, vous avez votre corps de fonction ou une expression. Dans l’exemple plus haut, vous pouvez voir que si votre fonction n’est composée que d’une seule expression, vous n’avez pas à mettre les accolades et le mot-clé return à votre fonction, ce qui rend la fonction très compacte ! Cela aide aussi à garder une discipline au niveau de la longueur des fonctions, en encourageant les fonctions courtes et la composition. De plus, personnellement, j’aime beaucoup cette syntaxe puisqu’elle nous ramène à ce que les fonctions pures sont : un ensemble d’entrées qui sont converties en sortie. D’un certain point de vue, je trouve qu’il est facile de visualiser ce qu’est une fonction à la base, avec la flèche qui indique une transition des éléments de la gauche vers le résultat de la droite.

Cette syntaxe courte existe également en C# et en Java, avec des règles similaires. À part la quantité de code à écrire, ce qui est le plus important à propos de cette syntaxe est le fait qu’il s’agisse d’une expression, que vous pouvez donc stocker comme vous le faites avec d’autres types de valeurs. En ce sens, l’expression « fonction anonyme » désigne assez bien cette syntaxe, puisqu’il s’agit finalement d’une fonction sans nom. La fonction comme expression existe depuis 1999, en JavaScript, depuis la troisième édition d’ECMAScript. La nouveauté d’ES2015 est la nouvelle syntaxe plus compacte et simple, pas la fonction comme expression.

C’est d’ailleurs important de noter que les fonctions fléchées et les fonctions ordinaires ne sont pas toujours interchangeables. Il existe en effet des différences majeures dans la façon dont les deux syntaxes gèrent le mot-clé this, et les fonctions fléchées ne peuvent pas être utilisées comme constructeurs (elles ne peuvent pas être appelées avec le mot-clé new). Très rapidement, si vous venez d’un langage orienté objet qui utilise les classes pour définir des objets, les choses fonctionnent assez différemment en JavaScript. En effet, ici, les « classes » sont plutôt des fonctions auxquelles on va assigner des fonctions à son prototype, et qui peuvent ensuite être instanciées à l’aide du mot-clé new (en plus de pouvoir être appelées normalement).

Dans un style de programmation plus fonctionnelle, les fonctions fléchées sont une façon très compacte et expressive de déclarer des fonctions, mais elles ne peuvent malgré tout pas toujours remplacer les fonctions traditionnelles, c’est donc à garder en tête.

Je n’attaquerai pas la question des fonctions génératrices ou async dans cet article, puisqu’elles sont plus à propos d’un comportement spécifique que de la façon dont on peut définir des fonctions. Cela dit, je souhaite quand même aborder rapidement les fonctions comme méthodes.

Normalement, lorsque vous créez un objet (que je garder un simple objet littéral JavaScript, pour les besoins de cet exemple), vous pouvez assigner des méthodes à votre objet en lui assignant des fonctions à ses propriétés :

Comme vous pouvez le voir, vous pouvez utiliser les deux notations vues plus haut dans ce type d’opération (tout en gardant en tête les différences de comportement). À partir de ES2015, il est toutefois possible de déclarer ces méthodes avec une notation de méthodes, qui ressemble à la façon dont on crée des fonctions nommées.

Comme pour les fonctions génératrices et async, je n’aborderai pas les méthodes get et set en ES2015, puisqu’elles sont un sujet entièrement différent. Cela dit, ces méthodes utilisent la syntaxe de méthode vue dans l’exemple précédent.

Voilà donc tout ce que nous avions à voir dans ce billet !

J’espère que vous avez maintenant plus de familiarité avec les différentes (et plus modernes) façons de rédiger des fonctions en JavaScript !

Restez à l’affut vendredi prochain pour un nouvel article !