Javascript ES6 - progammation fonctionnelle

Tps de lecture estimé:4 minutes 7 secondes

Javascript ES6 - programmation fonctionnelle

Voici une présentation rapide du la version ES6 du langage Javascript avec l'accent mis sur les possibilités de progammation fonctionelle.

Références/Sources:

Comment ne pas se faire avoir par javascript ?

Bréve Introduction

  // ---------------------------------------------
  // fonctions anonymes lambda (grosse flèche)  // ---------------------------------------------
  const doStuff = (a, b, c) => {...}
  // same as:
  function doStuff(a, b, c) {
  /*...*/
  }

  // ---------------------------------------------
  // déstructuration d'objet
  // ---------------------------------------------
  const doStuff = ({a, b, c}) => {
    console.log(a);
  }
  // identique à:
  const doStuff = (params) => {
    const {a, b, c} = params;
    console.log(a);
  }
  // identique à:
  const doStuff = (params) => {
    console.log(params.a);
  }

  // ---------------------------------------------
  // déstructuration de tableau
  // ---------------------------------------------
  const [a, b] = [1, 2];
  // identique à:
  const array = [1, 2];
  const a = array[0];
  const b = array[1];

Principes de base de progammation fonctionnelle en Javascrip ES6

  1. Éviter les fichiers longs (200 lignes max): décomposer les gros fichiers en modules plus petits et plus granulaires
  2. Éviter les fonctions longues (20 lignes max): refactoriser en fonctions plus petites
  3. Éviter les fonctions complexes: limiter les rappels imbriqués et une complexité cyclomatique élevée
  4. Éviter les méthodes avec un état mutable (c'est-à-dire une méthode qui change l'état de paramètre): construire et renvoyer un nouvel objet à la place (immuabilité):
  5. Éviter les mutations de tableaux (par exemple en utilisant des méthodes comme array.push): construire de nouveaux tableaux à la place
  6. Éviter les mot-clés let et var: utilisez plutôt const
    Exemple:

    // code avec let et mutabilité
    let discount;
    if (isLoggedIn) {
      if (cartTotal > 100  && !isFriday) {
        discount = 30;
      } else if (!isValuedCustomer) {
        discount = 20;
      } else {
        discount = 10;
      }
    } else {
      discount = 0;
    }
    
    // code avec const et immuabilité
    const getDiscount = ({isLoggedIn, cartTotal, isValuedCustomer}) => {
    if (!isLoggedIn) {
      return 0;
    }
    if (cartTotal > 100  && !isFriday()) {
      return 30;
    }
    if (!isValuedCustomer) {
      return 20;
    }
      return 10;
    }
  7. Éviter d'utiliser this
  8. Utiliser du code déclaratif: se focaliser (décrire) sur le résultat souhaité, et pas sur les instructions spécifiques
  9. Préférer les expressions aux instructions: privilégier les opérateurs ternaire et les lambda aux instructions if, return, switch, for, while
    Exemple:

    // code avec des instructions
    const calculateStuff = input => {
    if (input.x) {
      return superCalculator(input.x);
    }
      return dumbCalculator(input.y);
    };
    // code avec opérateur ternaire et expression lambda (plus simple)
    const calculateStuff = input => {return input.x ? superCalculator(input.x) : dumbCalculator(input.y);};
    // code avec opérateur ternaire uniquement (encore plus simple)
    const calculateStuff = input => input.x ? superCalculator(input.x) : dumbCalculator(input.y);
  10. Éviter de passer plusieurs paramètres aux fonctions (à cause : utiliser la destructuration d'objets
    Exemple:

    // appel avec plusieur paramètres indifférenciés
    const total = computeShoppingCartTotal(itemList, 10.0, 'USD');
    // appel avec un objet  de-structuré (paramètres différenciés)
    const computeShoppingCartTotal = ({ itemList, discount, currency }) => {/*...*/};
    const total = computeShoppingCartTotal({ itemList, discount: 10.0, currency: 'USD' });
  11. Favoriser le retour d'objet à partir de fonctions: Par exemple, utiliser plutôt const { user, status } = saveUser(...) que const result = saveUser(...);
  12. Éviter ou contrôler l'utilisation des exceptions et s'assurer de la cohérence des données de sortie avec et sans exception. Par exemple, une fonction peut renvoyer un tuple contenant à la fois son résultat et un code d'erreur (ou aucun si OK). Laisser le programme se planter plutôt que de récupérer toutes les exceptions.
  13. Utiliser des Application de fonction partielle (cf code)
  14. Autres astuces:

    • Marquer les arguments de fonction comme requis (cf code)
    • Utiliser des conditions pour court-circuiter des évaluations ou renvoyer des valeurs par défaut

      const getUserCity = user => user && user.address && user.address.city;
      const userCity = getUserCity(user) || "Detroit";
    • La négation d'une valeur deux fois (!!) est un excellent moyen de convertir n'importe quelle valeur en booléen (cf code)
    • Débugguer "in-place" en utilisant le fait que la fonction console.log() renvoie toujours false
    const add = (a, b) =>
      console.log('add', a, b)
      || (a + b);
    const User = ({email, name}) => (
      <>
        <Email value={console.log('email', email) || email} />
        <Name value={console.log('name', name) || name} />
      </>
    );

Configuration ESLint

ESLint est un outil pour l'analyse de code statique.
En étant correctement configuré, il permet d'éviter certains pièges dus à la permissivité du langage.

Installation

  • se placer dans le répertoire racine de votre de projet,
  • executer (syntaxe Debian Like) :npm i -D eslint;npm i -D eslint-plugin-fp
  • créez un fichier .eslintrc.yml dans le répertoire racine de votre projet qui implémentent les principes précédents sous forme de régles.
  env:
    es6: true

  plugins:
    fp

  rules:
  # rules will go in here
    max-lines:
    - warn
    - 200
    max-lines-per-function:
    - warn
    - 20
    complexity:
    - warn
    - 5
    max-nested-callbacks:
    - warn
    - 2
    max-depth:
    - warn
    - 3
    fp/no-mutation: warn
    no-param-reassign: warn
    fp/no-mutating-assign: warn
    fp/no-mutating-methods: warn
    fp/no-mutation: warn
    fp/no-this: warn
    fp/no-let: warn
    fp/no-loops: warn
    fp/no-mutating-assign: warn
    fp/no-mutating-methods: warn
    fp/no-mutation: warn
    fp/no-delete: warn
    max-params:
    - warn
    - 2
    fp/no-throw: warn

Article suivant