10 importanti funzioni di Lodash per sviluppatori JavaScript
Pubblicato: 2021-10-05Per gli sviluppatori JavaScript, Lodash non ha bisogno di presentazioni. Tuttavia, la biblioteca è vasta e spesso sembra opprimente. Non più!
Lodash, Lodash, Lodash. . . da dove comincio anche io!
C'è stato un tempo in cui l'ecosistema JavaScript era nascente; potrebbe essere paragonato al selvaggio west o a una giungla se vuoi, dove stavano succedendo molte cose, ma c'erano pochissime risposte per le frustrazioni e la produttività quotidiana degli sviluppatori.
Poi Lodash è entrato in scena, ed è stato come un diluvio che ha sommerso tutto. Fin dalle semplici esigenze quotidiane come l'ordinamento alle complesse trasformazioni della struttura dei dati, Lodash è stato caricato (sovraccarico, persino!) Con funzionalità che hanno trasformato la vita degli sviluppatori JS in pura felicità.

E dov'è Lodash oggi? Bene, ha ancora tutte le chicche che offriva inizialmente, e poi alcune, ma sembra aver perso la quota di mente nella comunità JavaScript. Come mai? Mi vengono in mente alcuni motivi:
- Alcune funzioni nella libreria Lodash erano (e sono tuttora) lente se applicate a elenchi di grandi dimensioni. Anche se questo non avrebbe mai influenzato il 95% dei progetti là fuori, sviluppatori influenti del restante 5% hanno dato a Lodash una cattiva pubblicità e l'effetto è sceso a cascata nella base.
- C'è una tendenza nell'ecosistema JS (potrebbe anche dire la stessa cosa della gente del Golang) in cui l'arroganza è più comune del necessario. Quindi, fare affidamento su qualcosa come Lodash è visto come stupido e viene abbattuto su forum come StackOverflow quando le persone suggeriscono tali soluzioni ("Cosa?! Usa un'intera libreria per qualcosa di simile? Posso combinare
filter()conreduce()per ottenere la stessa cosa in una semplice funzione!”). - Lodash è vecchio. Almeno per gli standard JS. È uscito nel 2012, quindi al momento della stesura sono passati quasi dieci anni. L'API è stata stabile e non è possibile aggiungere molte cose interessanti ogni anno (semplicemente perché non è necessario), il che genera noia per lo sviluppatore JS medio sovraeccitato.
A mio parere, non usare Lodash è una perdita significativa per le nostre basi di codice JavaScript. Ha dimostrato soluzioni eleganti e prive di bug per i problemi quotidiani che incontriamo al lavoro e il suo utilizzo renderà il nostro codice solo più leggibile e gestibile.
Detto questo, tuffiamoci in alcune delle funzioni Lodash comuni (o meno!) e vediamo quanto sia incredibilmente utile e bella questa libreria.
Clona. . . profondamente!
Poiché gli oggetti vengono passati per riferimento in JavaScript, crea un mal di testa per gli sviluppatori quando vogliono clonare qualcosa con la speranza che il nuovo set di dati sia diverso.
let people = [ { name: 'Arnold', specialization: 'C++', }, { name: 'Phil', specialization: 'Python', }, { name: 'Percy', specialization: 'JS', }, ]; // Find people writing in C++ let folksDoingCpp = people.filter((person) => person.specialization == 'C++'); // Convert them to 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' } ] */ Nota come nella nostra pura innocenza e nonostante le nostre buone intenzioni, l'array originale delle people mutato nel processo (la specializzazione di Arnold è cambiata da C++ a JS ) - un duro colpo all'integrità del sistema software sottostante! In effetti, abbiamo bisogno di un modo per creare una copia vera (profonda) dell'array originale.

Puoi forse obiettare che questo è un modo "sciocco" di codificare in JS; tuttavia, la realtà è un po' complicata. Sì, abbiamo a disposizione l'adorabile operatore destrutturatore, ma chiunque abbia provato a destrutturare oggetti e array complessi conosce il dolore. Quindi, c'è l'idea di utilizzare la serializzazione e la deserializzazione (forse JSON) per ottenere una copia profonda, ma rende solo il tuo codice più complicato per il lettore.
Al contrario, guarda quanto è sorprendentemente elegante e concisa la soluzione quando si usa Lodash:
const _ = require('lodash'); let people = [ { name: 'Arnold', specialization: 'C++', }, { name: 'Phil', specialization: 'Python', }, { name: 'Percy', specialization: 'JS', }, ]; let peopleCopy = _.cloneDeep(people); // Find people writing in C++ let folksDoingCpp = peopleCopy.filter( (person) => person.specialization == 'C++' ); // Convert them to 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' } ] */ Nota come l'array di people non viene toccato dopo la clonazione profonda (Arnold è ancora specializzato in C++ in questo caso). Ma soprattutto, il codice è semplice da capire.
Rimuovi i duplicati da un array
Rimuovere i duplicati da un array suona come un eccellente problema di intervista/lavagna (ricorda, in caso di dubbio, di lanciare una hashmap al problema!). E, naturalmente, puoi sempre scrivere una funzione personalizzata per farlo, ma cosa succede se incontri diversi scenari in cui rendere unici i tuoi array? Potresti scrivere molte altre funzioni per questo (e rischiare di incorrere in bug sottili), oppure potresti semplicemente usare Lodash!

Il nostro primo esempio di array univoci è piuttosto banale, ma rappresenta comunque la velocità e l'affidabilità che Lodash porta in tavola. Immagina di farlo scrivendo tu stesso tutta la logica personalizzata!
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 ]Si noti che l'array finale non è ordinato, il che, ovviamente, non è di alcun interesse qui. Ma ora immaginiamo uno scenario più complicato: abbiamo una serie di utenti che abbiamo estratto da qualche parte, ma vogliamo assicurarci che contenga solo utenti unici. Facile con 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 } ] */ In questo esempio, abbiamo usato il metodo uniqBy() per dire a Lodash che vogliamo che gli oggetti siano univoci sulla proprietà id . In una riga, abbiamo espresso ciò che avrebbe potuto richiedere 10-20 righe e introdotto più possibilità per i bug!
Ci sono molte più cose disponibili per rendere le cose uniche in Lodash e ti incoraggio a dare un'occhiata ai documenti.
Differenza di due array
Unione, differenza, ecc., potrebbero sembrare termini che è meglio lasciar perdere nelle noiose lezioni di teoria degli insiemi delle scuole superiori, ma emergono il più delle volte nella pratica quotidiana. È comune avere un elenco e voler fondere un altro elenco con esso o voler trovare quali elementi sono univoci rispetto a un altro elenco; per questi scenari, la funzione differenza è perfetta.

Iniziamo il viaggio della differenza partendo da uno scenario semplice: hai ricevuto un elenco di tutti gli ID utente nel sistema, nonché un elenco di quelli i cui account sono attivi. Come trovi gli ID inattivi? Semplice, vero?
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 ] E se, come accade in un ambiente più realistico, dovessi lavorare con una serie di oggetti invece di semplici primitive? Bene, Lodash ha un bel metodo differenceBy() per questo!
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' } ]Pulito, vero?!
Come differenza, ci sono altri metodi in Lodash per operazioni comuni sugli insiemi: unione, intersezione, ecc.
Array appiattiti
La necessità di appiattire gli array si presenta abbastanza spesso. Un caso d'uso è che hai ricevuto una risposta API e devi applicare alcune combo map() e filter() su un elenco complesso di oggetti/array nidificati per estrarre, ad esempio, gli ID utente, e ora ti rimane array di array. Ecco uno snippet di codice che descrive questa situazione:
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' }, ], }; // find user ids that placed postpaid orders (internal or external) const postpaidUserIds = []; for (const [orderType, orders] of Object.entries(orderData)) { postpaidUserIds.push(orders.filter((order) => order.type === 'postpaid')); } console.log(postpaidUserIds); Riesci a indovinare che aspetto ha postPaidUserIds ora? Suggerimento: è disgustoso!
[ [], [ { userId: 3, date: '2021-08-08', amount: 30, type: 'postpaid' }, { userId: 4, date: '2021-06-06', amount: 330, type: 'postpaid' } ] ] Ora, se sei una persona ragionevole, non vuoi scrivere una logica personalizzata per estrarre gli oggetti dell'ordine e disporli bene in una riga all'interno di un array. Basta usare il metodo flatten() e godersi l'uva:
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' } ] */ Nota che flatten() va in profondità solo di un livello. Cioè se i tuoi oggetti sono bloccati a due, tre o più livelli in profondità, flatten() ti deluderanno. In questi casi, Lodash ha il metodo flattenDeep() , ma flattenDeep() presente che l'applicazione di questo metodo su strutture molto grandi può rallentare le cose (come dietro le quinte, c'è un'operazione ricorsiva al lavoro).

L'oggetto/array è vuoto?
Grazie a come funzionano i valori e i tipi "falsi" in JavaScript, a volte qualcosa di semplice come controllare la vacuità provoca terrore esistenziale.

Come si controlla se un array è vuoto? Puoi verificare se la sua length è 0 o meno. Ora, come si controlla se un oggetto è vuoto? Beh... aspetta un attimo! È qui che entra in gioco quella sensazione di disagio e quegli esempi JavaScript contenenti cose come [] == false e {} == false iniziano a girarci intorno. Quando sei sotto pressione per fornire una funzionalità, mine antiuomo come queste sono l'ultima cosa di cui hai bisogno: renderanno il tuo codice difficile da capire e introdurranno incertezza nella tua suite di test.
Lavorare con i dati mancanti
Nel mondo reale, i dati ci ascoltano; non importa quanto lo desideriamo, raramente è snello e sano. Un tipico esempio è la mancanza di oggetti/array nulli in una struttura dati di grandi dimensioni ricevuta come risposta API.

Supponiamo di aver ricevuto il seguente oggetto come risposta API:
const apiResponse = { id: 33467, paymentRefernce: 'AEE3356T68', // `order` object missing processedAt: `2021-10-10 00:00:00`, }; Come mostrato, generalmente otteniamo un oggetto order nella risposta dall'API, ma non è sempre così. Quindi, cosa succede se abbiamo del codice che si basa su questo oggetto? Un modo sarebbe quello di codificare in modo difensivo, ma a seconda di quanto è annidato l'oggetto order , scriveremmo presto codice molto brutto se desideriamo evitare errori di runtime:
if ( apiResponse.order && apiResponse.order.payee && apiResponse.order.payee.address ) { console.log( 'The order was sent to the zip code: ' + apiResponse.order.payee.address.zipCode ); }Sì, molto brutto da scrivere, molto brutto da leggere, molto brutto da mantenere, e così via. Per fortuna, Lodash ha un modo semplice di affrontare tali situazioni.
const zipCode = _.get(apiResponse, 'order.payee.address.zipCode'); console.log('The order was sent to the zip code: ' + zipCode); // The order was sent to the zip code: undefined C'è anche la fantastica opzione di fornire un valore predefinito invece di undefined essere undefined per le cose mancanti:
const zipCode2 = _.get(apiResponse, 'order.payee.address.zipCode', 'NA'); console.log('The order was sent to the zip code: ' + zipCode2); // The order was sent to the zip code: NA Non so voi, ma get() è una di quelle cose che mi fanno get() le lacrime agli occhi. Non è niente di appariscente. Non c'è nessuna sintassi consultata o opzioni da memorizzare, ma guarda la quantità di sofferenza collettiva che può alleviare!
antirimbalzo
Nel caso tu non abbia familiarità, l'antirimbalzo è un tema comune nello sviluppo del frontend. L'idea è che a volte è vantaggioso lanciare un'azione non immediatamente ma dopo un po' di tempo (generalmente pochi millisecondi). Che cosa significa? Ecco un esempio.

Immagina un sito Web di e-commerce con una barra di ricerca (beh, qualsiasi sito Web/app Web in questi giorni!). Per una migliore UX, non vogliamo che l'utente debba premere invio (o peggio, premere il pulsante "cerca") per mostrare suggerimenti/anteprime in base al termine di ricerca. Ma la risposta ovvia è un po' carica: se aggiungiamo un ascoltatore di eventi a onChange() per la barra di ricerca e lanciamo una chiamata API per ogni sequenza di tasti, avremmo creato un incubo per il nostro backend; ci sarebbero troppe chiamate non necessarie (ad esempio, se si cerca “spazzola per tappeti bianchi”, ci saranno un totale di 18 richieste!) e quasi tutte saranno irrilevanti perché l'input dell'utente non è terminato.
La risposta sta nell'antirimbalzo e l'idea è questa: non inviare una chiamata API non appena il testo cambia. Attendi un po' di tempo (diciamo 200 millisecondi) e se a quel punto viene premuto un altro tasto, annulla il conteggio del tempo precedente e ricomincia ad aspettare. Di conseguenza, è solo quando l'utente si ferma (o perché sta pensando o perché ha finito e si aspetta una risposta) che inviamo una richiesta API al backend.
La strategia complessiva che ho descritto è complicata e non mi addentrerò nella sincronizzazione della gestione e della cancellazione del timer; tuttavia, l'effettivo processo di antirimbalzo è molto semplice se utilizzi Lodash.
const _ = require('lodash'); const axios = require('axios'); // This is a real dogs' API, by the way! const fetchDogBreeds = () => axios .get('https://dog.ceo/api/breeds/list/all') .then((res) => console.log(res.data)); const debouncedFetchDogBreeds = _.debounce(fetchDogBreeds, 1000); // after one second debouncedFetchDogBreeds(); // shows data after some time Se stai pensando setTimeout() avrei fatto lo stesso lavoro, beh, c'è di più! L'antirimbalzo di Lodash è dotato di molte potenti funzionalità; ad esempio, potresti voler assicurarti che l'antirimbalzo non sia indefinito. Cioè, anche se viene premuto un tasto ogni volta che la funzione sta per attivarsi (annullando così il processo complessivo), potresti voler assicurarti che la chiamata API venga effettuata comunque dopo, ad esempio, due secondi. Per questo, Lodash debounce() ha l'opzione maxWait :
const debouncedFetchDogBreeds = _.debounce(fetchDogBreeds, 150, { maxWait: 2000 }); // debounce for 250ms, but send the API request after 2 seconds anywayDai un'occhiata ai documenti ufficiali per un'immersione più profonda. Sono pieni di cose super importanti!
Rimuovi i valori da un array
Non so voi, ma io odio scrivere codice per rimuovere elementi da un array. Innanzitutto, devo ottenere l'indice dell'elemento, verificare se l'indice è effettivamente valido e, in tal caso, chiamare il metodo splice() e così via. Non riesco mai a ricordare la sintassi e quindi ho bisogno di cercare le cose tutto il tempo, e alla fine, mi rimane la fastidiosa sensazione di aver lasciato entrare uno stupido bug.

const greetings = ['hello', 'hi', 'hey', 'wave', 'hi']; _.pull(greetings, 'wave', 'hi'); console.log(greetings); // [ 'hello', 'hey' ]Si prega di notare due cose:
- L'array originale è stato modificato nel processo.
- Il metodo
pull()rimuove tutte le istanze, anche se sono presenti duplicati.
Esiste un altro metodo correlato chiamato pullAll() che accetta un array come secondo parametro, semplificando la rimozione di più elementi contemporaneamente. Concesso che potremmo semplicemente usare pull() con un operatore di diffusione, ma ricorda che Lodash è arrivato in un momento in cui l'operatore di diffusione non era nemmeno una proposta nella lingua!
const greetings2 = ['hello', 'hi', 'hey', 'wave', 'hi']; _.pullAll(greetings2, ['wave', 'hi']); console.log(greetings2); // [ 'hello', 'hey' ]Ultimo indice di un elemento
Il metodo indexOf indexOf() nativo di JavsScript è interessante, tranne quando sei interessato a scansionare l'array dalla direzione opposta! E ancora, sì, potresti semplicemente scrivere un ciclo decrescente e trovare l'elemento, ma perché non usare una tecnica molto più elegante?

Ecco una rapida soluzione Lodash utilizzando il metodo lastIndexOf() :
const integers = [2, 4, 1, 6, -1, 10, 3, -1, 7]; const index = _.lastIndexOf(integers, -1); console.log(index); // 7Sfortunatamente, non esiste una variante di questo metodo in cui possiamo cercare oggetti complessi o persino passare una funzione di ricerca personalizzata.
Cerniera lampo. decomprimi!

A meno che tu non abbia lavorato in Python, zip/unzip è un'utilità che potresti non notare o immaginare mai in tutta la tua carriera come sviluppatore JavaScript. E forse per una buona ragione: raramente c'è il tipo di disperato bisogno di zip/unzip come c'è per filter() , ecc. Tuttavia, è una delle migliori utility meno conosciute in circolazione e può aiutarti a creare codice succinto in alcune situazioni .
Contrariamente a quanto sembra, zip/unzip non ha nulla a che fare con la compressione. Invece, è un'operazione di raggruppamento in cui gli array della stessa lunghezza possono essere convertiti in un singolo array di array con elementi nella stessa posizione impacchettati insieme ( zip() ) e unzip() ). Sì, lo so, sta diventando confuso cercare di arrangiarsi con le parole, quindi diamo un'occhiata a un po' di codice:
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' ] ] I tre array originali sono stati convertiti in uno solo con due array. E ognuno di questi nuovi array rappresenta un singolo animale con tutti i suoi in un unico posto. Quindi, l'indice 0 ci dice che tipo di animale è, l'indice 1 ci dice la sua taglia e l'indice 2 ci dice il suo peso. Di conseguenza, è ora più facile lavorare con i dati. Dopo aver applicato tutte le operazioni necessarie sui dati, puoi suddividerlo nuovamente utilizzando unzip() e inviarlo alla fonte originale:
const animalData = _.unzip(groupedAnimals); console.log(animalData); // [ [ 'duck', 'sheep' ], [ 'small', 'large' ], [ 'less', 'more' ] ]L'utilità zip/unzip non è qualcosa che cambierà la tua vita da un giorno all'altro, ma cambierà la tua vita un giorno!
Conclusione
(Ho messo qui tutto il codice sorgente utilizzato in questo articolo per fartelo provare direttamente dal browser!)
I documenti Lodash sono pieni zeppi di esempi e funzioni che ti lasceranno a bocca aperta. In un'epoca in cui il masochismo sembra aumentare nell'ecosistema JS, Lodash è come una boccata d'aria fresca e consiglio vivamente di utilizzare questa libreria nei tuoi progetti!
