Fermer

avril 20, 2018

Programmation fonctionnelle avec des tableaux d'objets JavaScript


Nous considérons l'utilisation de map filter et reduce pour manipuler des tableaux d'objets, en utilisant des techniques empruntées à la programmation fonctionnelle.

une tâche commune dans n'importe quelle application JavaScript. Heureusement, de nouveaux opérateurs de gestion de tableaux map filter et reduce sont largement supportés. Bien que la documentation de ces fonctionnalités soit suffisante, elle montre souvent des cas d'utilisation très simples pour la mise en œuvre. Dans l'utilisation quotidienne, nous avons souvent besoin d'utiliser ces méthodes pour traiter des tableaux d'objets de données, ce qui est le scénario qui manque à la documentation. De plus, ces opérateurs sont souvent vus dans des langages fonctionnels et apportent à JavaScript une nouvelle perspective d'itération à travers des objets fonctionnels.

Dans cet article, nous allons décomposer quelques exemples d'utilisation de la carte réduire et filtrer pour manipuler des tableaux d'objets. Grâce à ces exemples, nous apprendrons à quel point les méthodes sont puissantes, tout en comprenant leur relation avec la programmation fonctionnelle.

Programmation fonctionnelle: les bonnes parties

La programmation fonctionnelle a de nombreux concepts qui vont au-delà de ce que nous sommes. essayant d'accomplir. Pour le contexte de cet article, nous allons discuter de certaines des bases absolues.

Tout au long des exemples, nous allons favoriser les expressions simples sur plusieurs instructions. Cela signifie que nous allons réduire considérablement le nombre de variables utilisées et utiliser à la place la composition de la fonction et le chaînage des méthodes chaque fois que cela est possible. Ce style de programmation réduit le besoin de maintenir l'état, ce qui correspond aux pratiques de programmation fonctionnelle.

Un avantage commun de l'utilisation de map et filter est que chaque opérateur crée un nouveau tableau. En créant de nouveaux tableaux au lieu de modifier ou de muter des données existantes, notre code sera plus facile à raisonner, puisque la mutation des données peut provoquer des effets secondaires inattendus.

Enfin, nous tirerons profit du fait que chaque opérateur est plus haut. fonction de commande. Autrement dit, chaque opérateur accepte une fonction de rappel en tant que paramètre. La fonction de rappel nous permet de personnaliser le comportement grâce à la délégation de fonction, un outil puissant pour la flexibilité et la lisibilité du code.

L'idée ici n'est pas d'être «entièrement fonctionnel» mais de tirer parti des concepts. Si ces concepts vous concernent, une feuille de triche contenant une liste de méthodes / fonctions JavaScript fréquemment utilisées dans la programmation fonctionnelle est disponible en téléchargement. Le Functional Programming Cheat Sheet est une excellente référence rapide à garder à portée de main.

Télécharger la feuille de triche maintenant

Arrows Everywhere / Function Expressions

En venant des anciennes bibliothèques JavaScript la "grosse flèche" peut sembler un peu étranger. Cet opérateur de flèche => est utilisé pour réduire la quantité de code nécessaire pour écrire une fonction. Au lieu d'écrire explicitement la fonction () avec une instruction return quand nous avons besoin d'une fonction simple, nous pouvons utiliser Identifier => Expression . Cela aide à rendre notre code plus facile à lire, en particulier lorsque vous utilisez des fonctions d'ordre supérieur, des méthodes qui prennent une fonction en paramètre. .map .reduce et .filter sont toutes des fonctions d'ordre supérieur

Sans expressions de fonction, nous pourrions écrire quelque chose comme ceci:

 Laisser cart = [
  { name: "Drink", price: 3.12 },
  { name: "Steak", price: 45.15},
  { name: "Drink", price: 11.01}
];

let steakOrders = cart.filter (fonction (obj) {
  return obj.name === "Steak"
});

// {name: "Steak", prix: 45.15} 

Avec l'opérateur flèche, on pourrait écrire le même code en omettant la fonction comme dans l'exemple ci-dessous:

 let steakOrders = cart.filter ((obj) = > {return obj.name === "Steak"});

// {name: "Steak", prix: 45.15} 

Cependant, nous pouvons aller plus loin car la plus grande partie de l'expression est déjà implicite quand on utilise un opérateur fléché. Le code peut encore être réduit:

 let steakOrders = cart.filter (obj => obj.name === "Steak");

// {name: "Steak", prix: 45.15} 

Dans cet exemple, nous pouvons voir que la flèche a aidé à définir une fonction concise dans l'instruction filter. Maintenant que nous avons vu comment la flèche peut améliorer la façon dont les expressions sont écrites, apprenons plus sur l'utilisation de la méthode filter

Filtering Object Arrays

La méthode filter crée un nouveau tableau avec tous les éléments qui réussissent le test implémenté par la fonction fournie. Lorsque vous utilisez la méthode de filtrage sur des objets, nous pouvons créer un ensemble restreint basé sur une ou plusieurs propriétés de l'objet.

Dans cet exemple, nous allons obtenir les objets de la collection avec le nom "Steak" en transmettant une fonction expression qui teste la valeur de la propriété name, obj => obj.name === "Steak" :

 let cart = [
  { name: "Drink", price: 3.12 },
  { name: "Steak", price: 45.15},
  { name: "Drink", price: 11.01}
];

Laissez steakOrders = cart.filter (obj => obj.name === "Steak");

// {name: "Steak", prix: 45.15} 

Considérons que nous avons besoin d'un sous-ensemble de données où nous devons filtrer sur plusieurs valeurs de propriétés. Nous pouvons accomplir cela en écrivant une fonction qui contient plusieurs tests:

 let expensiveDrinkOrders =
    cart.filter (x => x.name === "Drink" && x.price> 10);

// {name: "Drink", prix: 11.01} 

Lors du filtrage sur plusieurs valeurs, l'expression de la fonction peut devenir longue ce qui rend le code difficile à raisonner en un coup d'oeil. En utilisant quelques techniques, nous pouvons simplifier le code et le rendre plus gérable.

Une façon d'aborder le problème consiste à utiliser plusieurs filtres à la place de l'opérateur && . En enchaînant plusieurs filtres, nous pouvons rendre la déclaration plus facile à raisonner tout en produisant les mêmes résultats:

 let expensiveDrinkOrders = cart.filter (x => x.name === "Drink")
                               .filter (x => x.prix> 10);

// {name: "Boire", prix: 11.01}

Une autre façon d'exprimer un filtre complexe consiste à créer une fonction nommée. Cela nous permettra d'écrire le filtre d'une manière "lisible par l'homme":

 const drinksGreaterThan10 =
  obj => obj.name === "Buvez" && obj.price> 10;
let result = cart.filter (drinksGreaterThan10); 

Bien que cela fonctionne comme prévu, la valeur du prix est codée en dur. Nous pouvons optimiser la lisibilité et la flexibilité en permettant de fixer le prix à l'exécution en utilisant un paramètre

Au début, il peut sembler intuitif d'ajouter le paramètre avec obj de telle sorte qu'il se lise (obj, coût) coût est le prix variable:

 const drinksGreaterThan =
  (obj, coût) => obj.name === "Drink" && obj.price> cost;
Laisser result = cart.filter (drinksGreaterThan (10)); // Erreur 

Currying en JavaScript

Malheureusement, cela créerait une erreur car le filtre attend une fonction avec un seul paramètre et maintenant nous essayons d'en utiliser deux. Pour satisfaire les paramètres correctement, nous aurions besoin d'écrire l'instruction de filtre en tant que .filter (x => drinksGreaterThan (x, 10)) .

Pour fournir une meilleure solution, nous pouvons utiliser une programmation fonctionnelle technique appelée currying. Currying permet de traduire une fonction avec plusieurs arguments en une séquence de fonctions, ce qui nous permet de créer une parité avec d'autres signatures de fonctions

Déplaçons le paramètre cost vers une expression de fonction et réécrivons la fonction drinksGreaterThan en utilisant la curry. C'est juste une utilisation intelligente d'une fonction d'ordre supérieur, où drinksGreatThan devient une fonction qui accepte un coût et retourne une autre fonction qui accepte un obj :

 const drinksGreaterThan =
  cost => obj => obj.name === "Buvez" && obj.price> coût;
Laisser result = cart.filter (drinksGreaterThan (10));

// {name: "Drink", prix: 11.01} 

La fonction complete nous donne un filtre nommé avec une lisibilité et une réutilisabilité maximales.

Mapping Objects

La méthode map est un outil essentiel pour convertir et projeter des données. La méthode map crée un nouveau tableau avec les résultats de l'appel d'une fonction fournie sur chaque élément du tableau appelant.

Dans un scénario où nous consommons une source de données externe, nous pouvons recevoir plus de données que nécessaire. Au lieu de traiter l'ensemble de données complet, nous pouvons utiliser la carte pour projeter les données comme bon nous semble. Dans l'exemple suivant, nous recevrons des données comprenant plusieurs propriétés, dont la plupart ne sont pas utilisées dans notre vue actuelle.

L'objet initial contient: id name , prix coût et taille :

 let jsonData = [
  { id: 1, name: "Soda", price: 3.12, cost: 1.04, size: "4oz", },
  { id: 2, name: "Beer", price: 6.50, cost: 2.45, size: "8oz" },
  { id: 3, name: "Margarita", price: 12.99, cost: 4.45, size: "12oz" }
]; 

Pour notre vue, nous n'utiliserons que le propriétés de nom et de prix, donc nous allons utiliser la carte pour construire un nouvel ensemble de données:

 laissez drinkMenu = jsonData.map (x => ({nom: x.nom, prix: x.prix}));

// [{"name":"Soda","price":3.12}, {"name":"Beer","price":6.5}, {"name":"Margarita","price":12.99}] 

En utilisant la carte nous pouvons assigner des valeurs de chaque objet à un nouvel objet qui n'a que le nom et le prix.

Si la map expression de la fonction, nous pouvons assigner la fonction à une variable. Cette abstraction ne change pas la façon dont fonctionne la carte mais l'intention du code devient plus claire pour ceux qui ne connaissent peut-être pas le domaine.

En créant une méthode unique nommée toMenuItem nous pouvons immédiatement donner un contexte à notre code. L'instruction map devient auto-documentante car elle peut être lue à haute voix "données JSON, mapper à l'élément de menu".

 const toMenuItem = x => ({nom: x.nom, prix: x.prix});
laissez drinkMenu = jsonData.map (toMenuItem);

// [{"name":"Soda","price":3.12}, {"name":"Beer","price":6.5}, {"name":"Margarita","price":12.99}] 

En continuant avec cet exemple, nous utiliserons à nouveau la map pour appliquer une conversion de valeur. Supposons que nous voulons convertir les prix des menus existants de USD à Euro. Puisque map ne mute pas le tableau initial, nous n'avons pas besoin de nous inquiéter de l'état de l'instance drinkMenu en raison de notre conversion.

Utilisons une fonction similaire pour convertir les valeurs de prix, sauf cette fois, nous garderons toutes les propriétés disponibles pour l'objet. Pour nous assurer que nous copions chaque valeur, nous utiliserons le ... opérateur spread:

 const drinkMenuEuro = drinkMenu.map (x => ({... x, prix: (x.prix * 0.81) .toFixe (2)})

// [{"name":"Soda","price":"2.53"},{"name":"Beer","price":"5.27"},{"name":"Margarita","price":"10.52"}] 

Dans cet exemple, ... x (l'opérateur spread) fait beaucoup pour nous. Ce petit morceau de code assure que nous copions l'objet complet et ses propriétés en ne modifiant que la valeur du prix. L'avantage de l'utilisation de l'opérateur de propagation est que nous pouvons ajouter des propriétés supplémentaires plus tard à drinkMenu et ils seront inclus drinkMenuEuro automatiquement

Réduire avec des objets

Réduire est un sous-utilisé et parfois un opérateur de tableau mal compris. La méthode réduire applique une fonction à un accumulateur et à chaque élément du tableau (de gauche à droite) pour le réduire à une valeur unique.

Lors de l'utilisation de réduire avec un tableau d'objets, la valeur l'objet résultant de l'itération précédente. Si nous devons obtenir la valeur totale d'une propriété d'objets (c'est-à-dire obj.price ), nous devons d'abord mapper cette propriété sur une seule valeur:

 let cart = [
  { name: "Soda", price: 3.12 },
  { name: "Margarita", price: 12.99},
  { name: "Beer", price: 6.50}
];

let totalPrice = cart.reduce ((acc, next) => prix d'acc. + prix suivant);
// NaN parce que acc ne peut pas être à la fois un objet et un nombre

Laisser totalPrice = cart.map (obj => obj.price) .reduce ((acc, next) => acc + next);
// 22.61 

Dans l'exemple précédent, nous avons vu que lorsque nous réduisons un tableau d'objets, alors l'accumulateur est un objet. La méthode réduire est extrêmement utile sur des objets dans de bonnes conditions. Au lieu d'essayer de faire la somme du prix d'un objet, utilisons reduce pour trouver l'objet avec le plus gros prix:

 let mostExpensiveItem = cart.reduce ((acc, next) => prix.acc.prix> suivant: acc: prochain);

// {name: "Margarita", prix: 12.99} 

Ici, nous utilisons la fonctionnalité de réduire pour nous donner l'objet le plus grand.

Nous pouvons utiliser un délégué de fonction pour décrire notre intention. Cela aidera à clarifier l'expression à l'intérieur de l'opérateur de réduction. Notre dernière fonction lit "réduire par le plus grand prix":

 let byGreatestPrice = (article, suivant) => article.prix> prix suivant? item: suivant;
let mostExpensiveItem = cart.reduce (parGreatestPrice);

// {name: "Margarita", prix: 12.99} 

Conclusion

Dans cet article nous avons regardé l'utilisation de carte réduire et filtre pour manipuler des tableaux d'objets. Puisque ces opérateurs de tableau ne modifient pas l'état du tableau appelant, nous pouvons les utiliser efficacement sans avoir à craindre les effets secondaires. En utilisant des techniques empruntées à la programmation fonctionnelle, nous pouvons écrire de puissants opérateurs de tableaux expressifs. Grâce à la délégation de fonction, nous avons la possibilité de créer des noms de fonctions explicites pour créer du code lisible.

Si les exemples montrant carte réduisent et filtre ont piqué votre intérêt pour la programmation fonctionnelle, puis jetez un coup d'œil à la feuille de triche de programmation fonctionnelle pour plus d'exemples d'utilisation d'une approche fonctionnelle pour créer des applications JavaScript.

Découvrez la feuille de triche

Contenu connexe:


Les commentaires sont désactivés en mode prévisualisation.
[ad_2]
Source link