10 fonctions Lodash importantes pour les développeurs JavaScript
Pour les développeurs JavaScript, Lodash n'est plus à présenter. Cependant, cette bibliothèque est très vaste et peut parfois sembler intimidante. Mais plus maintenant !
Lodash, Lodash, Lodash… par où commencer ? 🤔
Il fut un temps où l'écosystème JavaScript était balbutiant ; on pourrait le comparer au Far West ou à une jungle, où beaucoup de choses se passaient sans qu'il y ait beaucoup de solutions aux frustrations et problèmes quotidiens des développeurs en termes de productivité.
C'est alors que Lodash est apparu, tel un raz-de-marée. Des besoins quotidiens les plus simples, comme le tri, aux transformations les plus complexes des structures de données, Lodash est arrivé avec une panoplie de fonctionnalités qui ont transformé la vie des développeurs JS en un pur plaisir.
Bienvenue, Lodash !
Et où en est Lodash aujourd'hui ? Il possède toujours tous les avantages initiaux, et même davantage, mais il semble avoir perdu de sa popularité auprès de la communauté JavaScript. Pourquoi ? Il y a plusieurs raisons possibles :
- Certaines fonctions de Lodash étaient (et sont toujours) lentes lorsqu'elles sont appliquées à de grandes listes. Bien que cela n'affecte qu'une minorité de projets (5 %), les développeurs influents de cette petite part ont donné une mauvaise image de Lodash, et cet effet a touché la base d'utilisateurs.
- Dans l'écosystème JS, il y a une tendance (valable aussi pour les développeurs Golang) où l'orgueil est plus courant que nécessaire. Ainsi, dépendre de Lodash est perçu comme une erreur, critiquée sur des forums comme StackOverflow quand des personnes suggèrent de telles solutions ("Quoi ?! Utiliser une bibliothèque entière pour une action aussi simple ? Je peux combiner `filter()` avec `reduce()` pour obtenir le même résultat en une simple fonction !").
- Lodash est une bibliothèque ancienne, du moins selon les standards JS. Elle est sortie en 2012, ce qui, au moment où j'écris ces lignes, fait presque dix ans. L'API est stable, et peu de choses excitantes peuvent être ajoutées chaque année (car ce n'est pas forcément nécessaire), ce qui peut engendrer un manque d'intérêt chez le développeur JS moyen.
À mon avis, ne pas utiliser Lodash est une perte importante pour nos bases de code JavaScript. Cette bibliothèque offre des solutions élégantes et sans bug aux problèmes quotidiens que nous rencontrons au travail. De plus, son utilisation ne fera qu'améliorer la lisibilité et la maintenabilité de notre code.
Ceci étant dit, plongeons dans certaines des fonctions courantes (ou non) de Lodash et voyons à quel point cette bibliothèque est incroyablement utile et bien conçue.
Cloner... en profondeur !
Puisque les objets sont passés par référence en JavaScript, cela crée un casse-tête pour les développeurs qui veulent cloner un objet en espérant que le nouvel ensemble de données soit différent.
let people = [
{
name: 'Arnold',
specialization: 'C++',
},
{
name: 'Phil',
specialization: 'Python',
},
{
name: 'Percy',
specialization: 'JS',
},
];
// Trouver les personnes qui codent en C++
let folksDoingCpp = people.filter((person) => person.specialization == 'C++');
// Les convertir en JS !
for (person of folksDoingCpp) {
person.specialization = 'JS';
}
console.log(folksDoingCpp);
// [ { name: 'Arnold', specialization: 'JS' } ]
console.log(people);
/*
[
{ name: 'Arnold', specialization: 'JS' },
{ name: 'Phil', specialization: 'Python' },
{ name: 'Percy', specialization: 'JS' }
]
*/
Remarquez que, malgré nos bonnes intentions, le tableau d'origine a été modifié (la spécialisation d'Arnold est passée de C++ à JS). Il s'agit d'un coup dur pour l'intégrité du système logiciel ! Nous avons donc besoin d'un moyen de créer une copie fidèle (en profondeur) du tableau initial.
Salut Dave, voici Dave !
On pourrait dire qu'il s'agit d'une mauvaise façon de coder en JS. Cependant, la réalité est plus complexe. Oui, nous avons l'opérateur de déstructuration à notre disposition, mais quiconque a essayé de déstructurer des objets et des tableaux complexes sait à quel point cela peut être pénible. De plus, l'utilisation de la sérialisation et désérialisation (via JSON par exemple) pour effectuer une copie en profondeur rendrait simplement votre code plus difficile à lire.
En revanche, observez à quel point la solution est élégante et concise avec Lodash :
const _ = require('lodash');
let people = [
{
name: 'Arnold',
specialization: 'C++',
},
{
name: 'Phil',
specialization: 'Python',
},
{
name: 'Percy',
specialization: 'JS',
},
];
let peopleCopy = _.cloneDeep(people);
// Trouver les personnes qui codent en C++
let folksDoingCpp = peopleCopy.filter(
(person) => person.specialization == 'C++'
);
// Les convertir en JS !
for (person of folksDoingCpp) {
person.specialization = 'JS';
}
console.log(folksDoingCpp);
// [ { name: 'Arnold', specialization: 'JS' } ]
console.log(people);
/*
[
{ name: 'Arnold', specialization: 'C++' },
{ name: 'Phil', specialization: 'Python' },
{ name: 'Percy', specialization: 'JS' }
]
*/
Remarquez que le tableau `people` est intact après le clonage en profondeur (Arnold est toujours spécialisé en C++ dans ce cas). Mais plus important encore, le code est facile à comprendre.
Supprimer les doublons d'un tableau
Supprimer les doublons d'un tableau est un excellent problème d'entretien/tableau blanc (en cas de doute, utilisez une table de hachage !). Bien sûr, on peut toujours créer une fonction sur mesure, mais que se passe-t-il si vous rencontrez différents scénarios pour lesquels vous avez besoin de rendre vos tableaux uniques ? Vous pouvez écrire plusieurs fonctions pour cela (et prendre le risque de faire face à des bugs subtils), ou vous pouvez simplement utiliser Lodash !

Notre premier exemple de tableaux uniques est plutôt trivial, mais il illustre la vitesse et la fiabilité de Lodash. Imaginez devoir écrire toute cette logique vous-même !
const _ = require('lodash');
const userIds = [12, 13, 14, 12, 5, 34, 11, 12];
const uniqueUserIds = _.uniq(userIds);
console.log(uniqueUserIds);
// [ 12, 13, 14, 5, 34, 11 ]
Notez que le tableau final n'est pas trié, mais cela n'a pas d'importance ici. Imaginons maintenant un scénario plus compliqué : nous avons un tableau d'utilisateurs que nous avons récupéré quelque part, mais nous voulons nous assurer qu'il ne contient que des utilisateurs uniques. C'est facile avec Lodash !
const _ = require('lodash');
const users = [
{ id: 10, name: 'Phil', age: 32 },
{ id: 8, name: 'Jason', age: 44 },
{ id: 11, name: 'Rye', age: 28 },
{ id: 10, name: 'Phil', age: 32 },
];
const uniqueUsers = _.uniqBy(users, 'id');
console.log(uniqueUsers);
/*
[
{ id: 10, name: 'Phil', age: 32 },
{ id: 8, name: 'Jason', age: 44 },
{ id: 11, name: 'Rye', age: 28 }
]
*/
Dans cet exemple, nous avons utilisé la méthode `uniqBy()` pour indiquer à Lodash que nous voulons que les objets soient uniques selon la propriété `id`. En une ligne, nous avons exprimé ce qui aurait pu prendre 10 à 20 lignes et augmenter le risque de bogues !
De nombreuses autres fonctionnalités sont disponibles pour rendre les choses uniques dans Lodash. Je vous invite à consulter la documentation.
Différence entre deux tableaux
Union, différence, etc. sont des termes que l'on associe volontiers aux cours de maths ennuyeux du lycée. Pourtant, ils se présentent plus souvent qu'on ne le pense dans la pratique. Il est fréquent d'avoir une liste et de vouloir la fusionner avec une autre, ou de vouloir trouver les éléments qui lui sont uniques par rapport à une autre. Pour ces scénarios, la fonction `difference` est idéale.
Bonjour A, au revoir B !
Commençons notre exploration de la différence avec un scénario simple : vous avez une liste de tous les identifiants d'utilisateurs du système, ainsi qu'une liste de ceux dont les comptes sont actifs. Comment trouver les identifiants inactifs ? C'est facile, non ?
const _ = require('lodash');
const allUserIds = [1, 3, 4, 2, 10, 22, 11, 8];
const activeUserIds = [1, 4, 22, 11, 8];
const inactiveUserIds = _.difference(allUserIds, activeUserIds);
console.log(inactiveUserIds);
// [ 3, 2, 10 ]
Et si, comme dans un cas plus réaliste, vous deviez utiliser un tableau d'objets au lieu de simples primitives ? Eh bien, Lodash a une méthode `differenceBy()` faite pour ça !
const allUsers = [
{ id: 1, name: 'Phil' },
{ id: 2, name: 'John' },
{ id: 3, name: 'Rogg' },
];
const activeUsers = [
{ id: 1, name: 'Phil' },
{ id: 2, name: 'John' },
];
const inactiveUsers = _.differenceBy(allUsers, activeUsers, 'id');
console.log(inactiveUsers);
// [ { id: 3, name: 'Rogg' } ]
N'est-ce pas génial ? !
Comme `difference`, il existe d'autres méthodes dans Lodash pour les opérations sur les ensembles classiques : union, intersection, etc.
Aplatir les tableaux
La nécessité d'aplatir les tableaux se présente assez souvent. L'un des cas d'utilisation est lorsque vous avez reçu une réponse d'une API et que vous devez appliquer une combinaison `map()` et `filter()` sur une liste complexe d'objets/tableaux imbriqués pour extraire, par exemple, les identifiants d'utilisateurs. Vous vous retrouvez alors avec des tableaux de tableaux. Voici un extrait de code qui illustre cette situation :
const orderData = {
internal: [
{ userId: 1, date: '2021-09-09', amount: 230.0, type: 'prepaid' },
{ userId: 2, date: '2021-07-07', amount: 130.0, type: 'prepaid' },
],
external: [
{ userId: 3, date: '2021-08-08', amount: 30.0, type: 'postpaid' },
{ userId: 4, date: '2021-06-06', amount: 330.0, type: 'postpaid' },
],
};
// Trouver les identifiants des utilisateurs qui ont passé des commandes postpayées (internes ou externes)
const postpaidUserIds = [];
for (const [orderType, orders] of Object.entries(orderData)) {
postpaidUserIds.push(orders.filter((order) => order.type === 'postpaid'));
}
console.log(postpaidUserIds);
Pouvez-vous deviner à quoi ressemble `postpaidUserIds` ? Un indice : ce n'est pas très joli !
[
[],
[
{ userId: 3, date: '2021-08-08', amount: 30, type: 'postpaid' },
{ userId: 4, date: '2021-06-06', amount: 330, type: 'postpaid' }
]
]
Si vous êtes une personne raisonnable, vous n'avez pas envie d'écrire une logique personnalisée pour extraire les objets de commande et les placer correctement dans un seul tableau. Utilisez simplement la méthode `flatten()` et savourez le résultat :
const flatUserIds = _.flatten(postpaidUserIds);
console.log(flatUserIds);
/*
[
{ userId: 3, date: '2021-08-08', amount: 30, type: 'postpaid' },
{ userId: 4, date: '2021-06-06', amount: 330, type: 'postpaid' }
]
*/
Notez que `flatten()` ne fonctionne qu'à un seul niveau de profondeur. En d'autres termes, si vos objets sont imbriqués sur deux, trois ou plus de niveaux, `flatten()` ne suffira pas. Dans ce cas, Lodash possède la méthode `flattenDeep()`, mais sachez que son utilisation sur de très grandes structures peut ralentir les choses (car il y a une opération récursive en arrière-plan).
L'objet/tableau est-il vide ?
En raison du fonctionnement des valeurs "fausses" et des types en JavaScript, une tâche aussi simple que la vérification du vide peut parfois générer une angoisse existentielle.

Comment vérifier si un tableau est vide ? Vous pouvez vérifier si sa longueur est égale à 0 ou non. Et comment vérifier si un objet est vide ? Eh bien… attendez une minute ! C'est là que ce sentiment de malaise s'installe et que des exemples JavaScript tels que `[] == false` et `{}` == false` commencent à nous tourner dans la tête. Lorsque l'on est sous pression pour fournir une fonctionnalité, ce genre de pièges est la dernière chose dont on a besoin, car cela rendra votre code difficile à comprendre et introduira de l'incertitude dans votre suite de tests.
Travailler avec des données manquantes
Dans le monde réel, les données ne font pas toujours ce qu'on voudrait. Il est rare qu'elles soient rationalisées et cohérentes. Un exemple typique est l'absence d'objets/tableaux nuls dans une grande structure de données reçue en réponse d'une API.

Supposons que nous recevions l'objet suivant comme réponse d'une API :
const apiResponse = {
id: 33467,
paymentRefernce: 'AEE3356T68',
// L'objet `order` est manquant
processedAt: `2021-10-10 00:00:00`,
};
Comme on l'a vu, nous obtenons normalement un objet de commande dans la réponse de l'API, mais ce n'est pas toujours le cas. Alors, que se passe-t-il si nous avons du code qui dépend de cet objet ? Une façon de faire serait de coder de manière défensive, mais en fonction du niveau d'imbrication de l'objet de commande, on finirait par écrire du code très laid si l'on veut éviter les erreurs à l'exécution :
if (
apiResponse.order &&
apiResponse.order.payee &&
apiResponse.order.payee.address
) {
console.log(
'La commande a été envoyée au code postal : ' +
apiResponse.order.payee.address.zipCode
);
}
🤢🤢 Oui, c'est moche à écrire, à lire, à maintenir, etc. Heureusement, Lodash a une façon simple de gérer ce genre de situation.
const zipCode = _.get(apiResponse, 'order.payee.address.zipCode');
console.log('La commande a été envoyée au code postal : ' + zipCode);
// La commande a été envoyée au code postal : undefined
Il existe aussi la possibilité de fournir une valeur par défaut au lieu de recevoir `undefined` pour les éléments manquants :
const zipCode2 = _.get(apiResponse, 'order.payee.address.zipCode', 'NA');
console.log('La commande a été envoyée au code postal : ' + zipCode2);
// La commande a été envoyée au code postal : NA
Je ne sais pas vous, mais `get()` est l'une des choses qui me font pleurer de joie. Ce n'est pas une fonctionnalité tape-à-l'œil. Il n'y a pas de syntaxe ou d'options à mémoriser, mais regardez le nombre de problèmes qu'elle peut régler ! 😇
Anti-rebond
Si vous n'êtes pas familier avec le concept, l'anti-rebond est une stratégie courante dans le développement front-end. L'idée est qu'il est parfois préférable de lancer une action après un certain temps (généralement quelques millisecondes) plutôt qu'immédiatement. Qu'est-ce que cela signifie ? Voici un exemple.

Imaginez un site de commerce électronique avec une barre de recherche (enfin, n'importe quel site Web/application Web de nos jours !). Pour une meilleure expérience utilisateur, nous ne voulons pas que l'utilisateur ait à appuyer sur Entrée (ou pire, à cliquer sur le bouton "Rechercher") pour voir des suggestions/aperçus en fonction de son terme de recherche. La réponse évidente est un peu problématique : si nous ajoutons un écouteur d'événement à `onChange()` pour la barre de recherche et lançons un appel API à chaque frappe, nous créerions un cauchemar pour notre back-end ; il y aurait trop d'appels inutiles (par exemple, si on recherche "brosse à tapis blanc", il y aurait 18 requêtes au total !) et la plupart ne seront pas pertinentes puisque la saisie de l'utilisateur n'est pas terminée.
La solution réside dans l'anti-rebond. L'idée est de ne pas envoyer d'appel API dès que le texte change. Attendez un certain temps (par exemple, 200 millisecondes) et, si pendant ce temps il y a une autre frappe, annulez le décompte du temps précédent et recommencez l'attente. Ce n'est donc que lorsque l'utilisateur fait une pause (soit parce qu'il réfléchit, soit parce qu'il a terminé et qu'il attend une réponse) que nous envoyons une requête API au back-end.
La stratégie globale que j'ai décrite est compliquée et je ne vais pas m'attarder sur la gestion du chronomètre et son annulation. Cependant, le processus d'anti-rebond est très simple si vous utilisez Lodash.
const _ = require('lodash');
const axios = require('axios');
// Voici une vraie API pour les chiens !
const fetchDogBreeds = () =>
axios
.get('https://dog.ceo/api/breeds/list/all')
.then((res) => console.log(res.data));
const debouncedFetchDogBreeds = _.debounce(fetchDogBreeds, 1000); // Après une seconde
debouncedFetchDogBreeds(); // Affiche les données après un certain temps
Si vous pensez que `setTimeout()` ferait le même travail, sachez qu'il y a plus ! L'anti-rebond de Lodash est livré avec de nombreuses fonctionnalités puissantes ; par exemple, vous voudrez peut-être vous assurer que le rebond ne soit pas infini. Autrement dit, même s'il y a une frappe à chaque fois que la fonction est sur le point d'être déclenchée (annulant ainsi le processus global), vous voudrez peut-être vous assurer que l'appel API est quand même effectué au bout de deux secondes, par exemple. Pour cela, `debounce()` de Lodash a l'option `maxWait` :
const debouncedFetchDogBreeds = _.debounce(fetchDogBreeds, 150, { maxWait: 2000 }); // Rebond pendant 250 ms, mais envoie la requête API après 2 secondes
Consultez la documentation officielle pour une étude plus approfondie. Elle regorge de fonctionnalités intéressantes !
Supprimer des valeurs d'un tableau
Je ne sais pas vous, mais je déteste écrire du code pour supprimer des éléments d'un tableau. Je dois d'abord obtenir l'index de l'élément, vérifier que cet index est valide, puis appeler la méthode `splice()`, etc. Je n'arrive jamais à me souvenir de la syntaxe, et je suis obligé de chercher des infos tout le temps, avec la vague impression que j'ai introduit un bug stupide.

const greetings = ['hello', 'hi', 'hey', 'wave', 'hi']; _.pull(greetings, 'wave', 'hi'); console.log(greetings); // [ 'hello', 'hey' ]
Veuillez noter deux choses :
- Le tableau d'origine a été modifié.
- La méthode `pull()` supprime toutes les occurrences, même s'il y a des doublons.
Il existe une méthode connexe appelée `pullAll()` qui accepte un tableau en second paramètre, ce qui facilite la suppression de plusieurs éléments à la fois. Bien sûr, on pourrait utiliser `pull()` avec l'opérateur de déstructuration, mais souvenez-vous que Lodash est apparu à une époque où l'opérateur de déstructuration n'était même pas une proposition dans le langage !
const greetings2 = ['hello', 'hi', 'hey', 'wave', 'hi']; _.pullAll(greetings2, ['wave', 'hi']); console.log(greetings2); // [ 'hello', 'hey' ]
Dernier index d'un élément
La méthode native `indexOf()` de JavaScript est bien, sauf quand vous voulez parcourir le tableau dans le sens inverse ! Encore une fois, vous pourriez écrire une boucle décrémentielle et trouver l'élément, mais pourquoi ne pas utiliser une technique plus élégante ?

Voici une solution Lodash rapide utilisant la méthode `lastIndexOf()` :
const integers = [2, 4, 1, 6, -1, 10, 3, -1, 7]; const index = _.lastIndexOf(integers, -1); console.log(index); // 7
Malheureusement, il n'existe pas de variante de cette méthode permettant de rechercher des objets complexes, ou même de passer une fonction de recherche personnalisée.
Zipper. Dézipper !

Si vous n'avez jamais travaillé en Python, `zip/unzip` sont des utilitaires que vous n'aurez peut-être jamais remarqués ou imaginés pendant votre carrière de développeur JavaScript. Et peut-être à juste titre : le besoin de zipper/dézipper n'est pas aussi courant que celui de `filter()`, etc. Pourtant, il s'agit d'un outil intéressant et méconnu qui peut vous aider à créer du code plus concis dans certaines situations.
Contrairement à ce que l'on pourrait penser, `zip/unzip` n'ont rien à voir avec la compression. Il s'agit plutôt d'une opération de regroupement dans laquelle des tableaux de même longueur peuvent être transformés en un seul tableau de tableaux avec les éléments à la même position regroupés (`zip()`) et inversement (`unzip()`). Essayons de clarifier avec un peu de code :
const animals = ['duck', 'sheep']; const sizes = ['small', 'large']; const weight = ['less', 'more']; const groupedAnimals = _.zip(animals, sizes, weight); console.log(groupedAnimals); // [ [ 'duck', 'small', 'less' ], [ 'sheep', 'large', 'more' ] ]
Les trois tableaux d'origine ont été transformés en un seul tableau de deux tableaux. Et chacun de ces nouveaux tableaux représente un seul animal avec toutes ses caractéristiques au même endroit. Ainsi, l'index 0 nous indique le type d'animal, l'index 1 sa taille et l'index 2 son poids. Les données sont donc plus faciles à utiliser. Une fois que vous avez effectué les opérations nécessaires sur ces données, vous pouvez les décomposer à nouveau avec `unzip()` et obtenir le résultat original :
const animalData = _.unzip(groupedAnimals); console.log(animalData); // [ [ 'duck', 'sheep' ], [ 'small', 'large' ], [ 'less', 'more' ] ]
L'utilitaire `zip/unzip` ne va pas changer votre vie du jour au lendemain, mais il vous sera utile un jour !
Conclusion 👨🏫
(J'ai mis tout le code source utilisé dans cet article ici, vous pouvez donc l'essayer directement depuis votre navigateur !)
La documentation de Lodash regorge d'exemples et de fonctions étonnantes. À une époque où le masochisme semble augmenter dans l'écosystème JS, Lodash est comme une bouffée d'air frais, et je vous recommande vivement d'utiliser cette bibliothèque dans vos projets !