Fonctions flèches JavaScript: pourquoi elles sont nécessaires, comment les gérer, quand les utiliser et quand elles ne le sont pas

L'une des innovations les plus notables du JavaScript moderne est l'apparition de fonctions fléchées, parfois appelées fonctions fléchées «grasses». Lors de la déclaration de telles fonctions, ils utilisent une combinaison spéciale de caractères - => .

Les fonctions fléchées ont deux avantages principaux par rapport aux fonctions traditionnelles. Le premier est une syntaxe très pratique et compacte. La seconde est que l'approche à utiliser avec this dans les fonctions fléchées semble plus intuitive que dans les fonctions ordinaires.

image

Parfois, ces avantages et d'autres conduisent au fait que la syntaxe des flèches a une préférence inconditionnelle par rapport à d'autres façons de déclarer des fonctions. Par exemple, la configuration eslint populaire d'Airbnb oblige chaque fois qu'une fonction anonyme est créée, une telle fonction serait en forme de flèche.

Cependant, comme d'autres concepts et mécanismes utilisés dans la programmation, les fonctions fléchées ont leurs avantages et leurs inconvénients. Leur utilisation peut provoquer des effets secondaires négatifs. Pour utiliser correctement les fonctions fléchées, vous devez connaître les éventuels problèmes qui leur sont associés.

Le matériel, dont nous publions la traduction aujourd'hui, se concentrera sur le fonctionnement des fonctions fléchées. Nous considérerons ici les situations dans lesquelles leur utilisation peut améliorer le code et les situations dans lesquelles elles ne devraient pas être utilisées.

Comprend des fonctions fléchées en JavaScript


Les fonctions fléchées en JavaScript sont quelque chose comme les fonctions lambda en Python et les blocs en Ruby.

Ce sont des fonctions anonymes avec une syntaxe spéciale qui prennent un nombre fixe d'arguments et fonctionnent dans le contexte de la portée qui les inclut, c'est-à-dire dans le contexte de la fonction ou d'un autre code dans lequel elles sont déclarées.

Parlons de cela plus en détail.

▍ Fonctions flèches de syntaxe


Les fonctions fléchées sont construites selon un schéma unique, tandis que la structure des fonctions peut être, dans des cas particuliers, simplifiée. La structure de base de la fonction flèche ressemble à ceci:

 (argument1, argument2, ... argumentN) => { //   } 

La liste des arguments de la fonction est entre parenthèses, suivie d'une flèche composée de caractères = et > , puis vient le corps de la fonction entre accolades.

Ceci est très similaire au fonctionnement des fonctions ordinaires, les principales différences sont que le mot-clé function est omis ici et une flèche est ajoutée après la liste des arguments.

Dans certains cas, cependant, les fonctions flèches simples peuvent être déclarées en utilisant des constructions beaucoup plus compactes.

Considérez la syntaxe utilisée si le corps de la fonction est représenté par une seule expression. Il vous permet de vous passer de crochets qui encadrent le corps de la fonction et élimine la nécessité de renvoyer explicitement les résultats de l'évaluation d'une expression, car ce résultat sera renvoyé automatiquement. Par exemple, cela pourrait ressembler à ceci:

 const add = (a, b) => a + b; 

Voici une autre variante de la notation abrégée de la fonction, utilisée lorsque la fonction n'a qu'un seul argument.

 const getFirst = array => array[0]; 

Comme vous pouvez le voir, les parenthèses entourant la liste d'arguments sont omises ici. De plus, le corps de la fonction, qui dans cet exemple est représenté par une seule commande, est également écrit sans crochets. Plus tard, nous parlerons davantage des avantages de ces conceptions.

▍Retourner les objets et les fonctions de flèche d'enregistrement court


Lorsque vous travaillez avec des fonctions fléchées, certaines constructions de syntaxe plus complexes sont également utilisées, qui sont utiles à connaître.

Par exemple, essayez d'utiliser une expression sur une seule ligne pour revenir d'une fonction littérale d'objet. Il peut sembler, étant donné ce que nous savons déjà sur les fonctions fléchées, qu'une déclaration de fonction ressemblera à ceci:

 (name, description) => {name: name, description: description}; 

Le problème avec ce code est son ambiguïté. À savoir, les accolades que nous voulons utiliser pour décrire le littéral de l'objet ressemblent à ce que nous essayons d'y enfermer le corps d'une fonction.

Afin d'indiquer au système que nous entendons l'objet littéral, nous devons le mettre entre parenthèses:

 (name, description) => ({name: name, description: description}); 

▍ Fonctions fléchées et leur contexte d'exécution


Contrairement aux autres fonctions, les fonctions fléchées n'ont pas leur propre contexte d'exécution .

En pratique, cela signifie qu'ils héritent des entités this et des arguments de la fonction parent.

Par exemple, comparez les deux fonctions présentées dans le code suivant. L'un d'eux est ordinaire, le second est une flèche.

 const test = { name: 'test object', createAnonFunction: function() {   return function() {     console.log(this.name);     console.log(arguments);   }; }, createArrowFunction: function() {   return () => {     console.log(this.name);     console.log(arguments);   }; } }; 

Il existe un objet de test avec deux méthodes. Chacun d'eux est une fonction qui crée et renvoie une fonction anonyme. La différence entre ces méthodes est seulement que dans la première d'entre elles, l'expression fonctionnelle traditionnelle est utilisée et dans la fonction de la deuxième flèche.

Si nous expérimentons ce code dans la console, en passant les mêmes arguments aux méthodes de l'objet, alors bien que les méthodes semblent très similaires, nous obtiendrons des résultats différents:

 > const anon = test.createAnonFunction('hello', 'world'); > const arrow = test.createArrowFunction('hello', 'world'); > anon(); undefined {} > arrow(); test object { '0': 'hello', '1': 'world' } 

Une fonction anonyme a son propre contexte, donc lorsqu'elle est appelée, lorsque vous appelez test.name , la valeur de la propriété name de l'objet ne sera pas test.name , et lorsque vous appelez des arguments , la liste des arguments de la fonction qui a été utilisée pour créer et renvoyer la fonction sous enquête ne sera pas affichée.

Dans le cas d'une fonction flèche, il s'avère que son contexte coïncide avec le contexte de la fonction qui l'a créée, ce qui lui donne accès à la fois à la liste des arguments passés par cette fonction et à la propriété name de l'objet dont la méthode est cette fonction.

Situations dans lesquelles les fonctions fléchées améliorent le code


▍Traitement des listes de valeurs


Les fonctions lambda traditionnelles, ainsi que les fonctions fléchées, après leur apparition en JavaScript, sont généralement utilisées dans les situations où une certaine fonction est appliquée à chaque élément d'une certaine liste.

Par exemple, s'il existe un tableau de valeurs qui doit être converti à l'aide de la méthode des tableaux de map , une fonction de flèche est idéale pour décrire une telle conversion:

 const words = ['hello', 'WORLD', 'Whatever']; const downcasedWords = words.map(word => word.toLowerCase()); 

Voici un exemple extrêmement courant d'utilisation similaire des fonctions fléchées, qui consiste à travailler avec les propriétés des objets:

 const names = objects.map(object => object.name); 

De même, si au lieu des boucles for traditionnelles, ils utilisent des boucles forEach modernes basées sur un forEach , alors les fonctions fléchées utilisent this entité parent, rend leur utilisation intuitive:

 this.examples.forEach(example => { this.runExample(example); }); 

▍ Promesses et chaînes de promesses


Une autre situation où les fonctions fléchées vous permettent d'écrire du code plus propre et plus compréhensible est représentée par des constructions logicielles asynchrones.

Ainsi, les promesses simplifient considérablement le travail avec du code asynchrone. Dans le même temps, même si vous préférez utiliser la construction async / wait , vous ne pouvez pas vous passer de comprendre les promesses , car cette construction est basée sur elles.

Cependant, lorsque vous utilisez des promesses, vous devez déclarer des fonctions qui sont appelées après la fin du code asynchrone ou la fin de l'appel asynchrone à une API.

C'est un endroit idéal pour utiliser les fonctions fléchées, surtout si la fonction résultante a un certain état, se réfère à quelque chose dans l'objet. Par exemple, cela pourrait ressembler à ceci:

 this.doSomethingAsync().then((result) => { this.storeResult(result); }); 

▍ Transformation d'objet


Un autre cas d'utilisation courant pour les fonctions fléchées consiste à encapsuler des transformations d'objets.

Par exemple, dans Vue.js, il existe un modèle commun pour inclure des fragments de stockage Vuex directement dans un composant Vue à l'aide de mapState .

Cette opération comprend les déclarations d'un ensemble de «convertisseurs» qui sélectionnent exactement ce qui est nécessaire pour un composant particulier à partir de l'état complet initial.

Ces transformations simples sont l'endroit idéal pour utiliser les fonctions fléchées. Par exemple:

 export default { computed: {   ...mapState({     results: state => state.results,     users: state => state.users,   }); } } 

Situations dans lesquelles les fonctions fléchées ne doivent pas être utilisées


▍ Méthodes d'objet


Il existe un certain nombre de situations dans lesquelles l'utilisation des fonctions fléchées n'est pas une bonne idée. Les fonctions fléchées, si elles sont utilisées à la légère, non seulement n'aident pas les programmeurs, mais deviennent également une source de problèmes.

La première de ces situations consiste à utiliser les fonctions fléchées comme méthodes d'objet. Le contexte d'exécution et le this , spécifique aux fonctions traditionnelles, sont ici importants.

À une certaine époque, il était courant d'utiliser une combinaison de propriétés de classe et de fonctions fléchées pour créer des méthodes avec «liaison automatique», c'est-à-dire celles qui peuvent être utilisées par les gestionnaires d'événements, mais qui restent liées à la classe. Cela ressemblait à ceci:

 class Counter { counter = 0; handleClick = () => {   this.counter++; } } 

En utilisant une construction similaire, même si la fonction handleClick appelée par le gestionnaire d'événements, et non dans le contexte d'une instance de la classe Counter , cette fonction avait accès aux données de cette instance.

Cependant, cette approche présente de nombreux inconvénients auxquels ce matériel est consacré.

Bien que l'utilisation d'une fonction flèche ici, bien sûr, soit un moyen pratique de lier une fonction, le comportement de cette fonction est loin d'être intuitif à bien des égards, gênant les tests et créant des problèmes dans des situations où, par exemple, ils essaient d'utiliser l'objet correspondant comme prototype.

Dans de tels cas, au lieu des fonctions fléchées, utilisez des fonctions ordinaires et, si nécessaire, liez-leur une instance de l'objet dans le constructeur:

 class Counter { counter = 0; handleClick() {   this.counter++; } constructor() {   this.handleClick = this.handleClick.bind(this); } } 

Chains Longues chaînes d'appel


Les fonctions fléchées peuvent devenir une source de problèmes si elles sont prévues pour être utilisées dans de nombreuses combinaisons différentes, en particulier, dans de longues chaînes d'appels de fonctions.

La principale raison de ces problèmes, comme lors de l'utilisation de fonctions anonymes, est qu'ils donnent des résultats extrêmement peu informatifs de la trace de la pile d'appels .

Ce n'est pas si mal si, par exemple, il n'y a qu'un seul niveau d'imbrication des appels de fonction, disons, si nous parlons de la fonction utilisée dans l'itérateur. Cependant, si toutes les fonctions utilisées sont déclarées comme des fonctions fléchées et que ces fonctions s'appellent les unes les autres, alors si une erreur se produit, il ne sera pas facile de comprendre ce qui se passe. Les messages d'erreur ressembleront à ceci:

 {anonymous}() {anonymous}() {anonymous}() {anonymous}() {anonymous}() 

▍ Fonctions avec contexte dynamique


La dernière des situations dont nous discutons dans lesquelles les fonctions fléchées peuvent devenir une source de problèmes est de les utiliser là où vous avez besoin d'une dynamique de this liaison.

Si des fonctions fléchées sont utilisées dans de telles situations, la dynamique de this liaison ne fonctionnera pas. Cette surprise désagréable peut amener à réfléchir aux raisons de ce qui arrive à ceux qui doivent travailler avec du code dans lequel les fonctions fléchées sont utilisées de manière incorrecte.

Voici quelques éléments à garder à l'esprit lorsque vous envisagez d'utiliser les fonctions fléchées:

  • Les gestionnaires d'événements sont appelés avec this lié à l' currentTarget événement currentTarget .
  • Si vous utilisez toujours jQuery, considérez que la plupart des méthodes jQuery le lient à l'élément DOM sélectionné.
  • Si vous utilisez Vue.js, les méthodes et les fonctions calculées le lient généralement au composant Vue.

Bien entendu, les fonctions fléchées peuvent être utilisées intentionnellement afin de modifier le comportement standard des mécanismes logiciels. Mais, en particulier dans les cas avec jQuery et Vue, cela entre souvent en conflit avec le fonctionnement normal du système, ce qui conduit au fait que le programmeur ne peut pas comprendre pourquoi un code qui semble complètement normal refuse soudainement de fonctionner.

Résumé


Les fonctions fléchées sont une merveilleuse nouvelle fonctionnalité JavaScript. Ils permettent, dans de nombreuses situations, d'écrire du code plus pratique qu'auparavant. Mais, comme c'est le cas avec d'autres fonctionnalités, elles présentent à la fois des avantages et des inconvénients. Par conséquent, vous devez utiliser les fonctions fléchées là où elles peuvent être utiles, sans les considérer comme un remplacement complet des fonctions ordinaires.

Chers lecteurs! Avez-vous rencontré des situations dans lesquelles l'utilisation des fonctions fléchées entraîne des erreurs, des désagréments ou un comportement inattendu des programmes?

Source: https://habr.com/ru/post/fr428566/


All Articles