
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
-
Éviter les fichiers longs (200 lignes max): décomposer les gros fichiers en modules plus petits et plus granulaires
-
Éviter les fonctions longues (20 lignes max): refactoriser en fonctions plus petites
-
Éviter les fonctions complexes: limiter les rappels imbriqués et une complexité cyclomatique élevée
-
É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é):
-
Éviter les mutations de tableaux (par exemple en utilisant des méthodes comme
array.push
): construire de nouveaux tableaux à la place -
Éviter les mot-clés
let
etvar
: utilisez plutôtconst
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; }
-
Éviter d'utiliser
this
-
Utiliser du code déclaratif: se focaliser (décrire) sur le résultat souhaité, et pas sur les instructions spécifiques
-
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);
-
É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' });
-
Favoriser le retour d'objet à partir de fonctions: Par exemple, utiliser plutôt
const { user, status } = saveUser(...)
queconst result = saveUser(...);
-
É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.
-
Utiliser des Application de fonction partielle (cf code)
-
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 toujoursfalse
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