10 vigtige Lodash-funktioner for JavaScript-udviklere

For JavaScript-udviklere behøver Lodash ingen introduktion. Biblioteket er dog stort og føles ofte overvældende. Ikke mere!

Lodash, Lodash, Lodash. . . hvor skal jeg overhovedet starte! 🤔

Der var engang, hvor JavaScript-økosystemet var begyndende; det kunne sammenlignes med det vilde vesten eller en jungle om man vil, hvor der foregik meget, men der var meget få svar på hverdagens udviklerfrustrationer og produktivitet.

Derefter Lodash kom ind på scenen, og det føltes som en oversvømmelse, der sænkede alting. Lige fra simple hverdagsbehov som sortering til komplekse datastrukturtransformationer kom Lodash fyldt (overbelastet, endda!) med funktionalitet, der forvandlede JS-udvikleres liv til ren og skær lyksalighed.

Hej, Lodash!

Og hvor er Lodash i dag? Nå, det har stadig alle de lækkerier, det tilbød i starten, og så nogle, men det ser ud til at have mistet sin andel i JavaScript-fællesskabet. Hvorfor? Jeg kan komme i tanke om et par grunde:

  • Nogle funktioner i Lodash-biblioteket var (og er stadig) langsomme, når de blev anvendt på store lister. Selvom dette aldrig ville have påvirket 95 % af projekterne derude, gav indflydelsesrige udviklere fra de resterende 5 % Lodash et dårligt tryk, og effekten fossede ned i græsrødderne.
  • Der er en tendens i JS-økosystemet (kan endda sige det samme om Golang-folkene), hvor hybris er mere almindelig end nødvendigt. Så at stole på noget som Lodash bliver set som dumt og bliver skudt ned på fora som StackOverflow, når folk foreslår sådanne løsninger (“Hvad?! Brug et helt bibliotek til sådan noget? Jeg kan kombinere filter() med reduce() for at opnå det samme i en simpel funktion!”).
  • Lodash er gammel. I hvert fald efter JS-standarder. Den udkom i 2012, så i skrivende stund er der gået næsten ti år. API’et har været stabilt, og der kan ikke tilføjes mange spændende ting hvert år (simpelthen fordi det ikke er nødvendigt), hvilket genererer kedsomhed for den gennemsnitlige overspændte JS-udvikler.

Efter min mening er ikke brug af Lodash et betydeligt tab for vores JavaScript-kodebaser. Det har bevist fejlfri og elegante løsninger til hverdagsproblemer, vi støder på på arbejdet, og brugen af ​​det vil kun gøre vores kode mere læsbar og vedligeholdelig.

Med det sagt, lad os dykke ned i nogle af de almindelige (eller ej!) Lodash-funktioner og se, hvor utroligt nyttigt og smukt dette bibliotek er.

Klon . . . dybt!

Da objekter sendes ved reference i JavaScript, skaber det hovedpine for udviklere, når de vil klone noget med håbet om, at det nye datasæt er anderledes.

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' }
]
*/

Læg mærke til, hvordan i vores rene uskyld og på trods af vores gode intentioner, muterede det oprindelige folk-array i processen (Arnolds specialisering ændrede sig fra C++ til JS) – et stort slag for integriteten af ​​det underliggende softwaresystem! Faktisk har vi brug for en måde at lave en ægte (dyb) kopi af det originale array.

Hej Dave, mød Dave!

Du kan måske argumentere for, at dette er en “fjol” måde at kode på i JS; virkeligheden er dog lidt kompliceret. Ja, vi har den dejlige destruktureringsoperatør til rådighed, men enhver, der har forsøgt at destrukturere komplekse genstande og arrays, kender smerten. Så er der ideen om at bruge serialisering og de-serialisering (måske JSON) for at opnå dyb kopiering, men det gør kun din kode mere rodet for læseren.

Se derimod, hvor fantastisk elegant og kortfattet løsningen er, når Lodash bliver brugt:

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' }
]
*/

Læg mærke til, hvordan folk-arrayet er uberørt efter dyb kloning (Arnold er stadig specialiseret i C++ i dette tilfælde). Men endnu vigtigere, koden er ligetil at forstå.

  5 Enterprise-klare cloud-sårbarhedsscannere til AWS, GCP, Azure og mere

Fjern dubletter fra et array

At fjerne dubletter fra et array lyder som et fremragende interview/whiteboard-problem (husk, når du er i tvivl, smid et hashmap efter problemet!). Og du kan selvfølgelig altid skrive en brugerdefineret funktion for at gøre det, men hvad nu hvis du støder på flere forskellige scenarier, hvor du kan gøre dine arrays unikke? Du kan skrive flere andre funktioner til det (og risikere at løbe ind i subtile fejl), eller du kan bare bruge Lodash!

Vores første eksempel på unikke arrays er ret trivielt, men det repræsenterer stadig den hastighed og pålidelighed, som Lodash bringer til bordet. Forestil dig at gøre dette ved at skrive al den tilpassede logik selv!

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 ]

Bemærk, at det endelige array ikke er sorteret, hvilket selvfølgelig ikke er af betydning her. Men lad os nu forestille os et mere kompliceret scenarie: vi har en række brugere, vi hentede fra et sted, men vi vil sikre os, at det kun indeholder unikke brugere. Nemt med 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 }
]
*/

I dette eksempel brugte vi uniqBy()-metoden til at fortælle Lodash, at vi ønsker, at objekterne skal være unikke på id-egenskaben. I én linje udtrykte vi, hvad der kunne have taget 10-20 linjer og introduceret mere mulighed for fejl!

Der er meget mere tilgængeligt omkring at gøre ting unikke i Lodash, og jeg opfordrer dig til at tage et kig på dokumenter.

Forskellen på to arrays

Union, forskel osv. lyder måske som udtryk, der bedst efterlades i kedelige gymnasieforelæsninger om sætteori, men de dukker oftere op i hverdagens praksis. Det er almindeligt at have en liste og ønsker at flette en anden liste med den eller ønsker at finde, hvilke elementer der er unikke for den sammenlignet med en anden liste; til disse scenarier er forskelsfunktionen perfekt.

Hej, A. Farvel, B!

Lad os begynde forskellens rejse ved at tage et simpelt scenarie: du har modtaget en liste over alle bruger-id’erne i systemet, samt en liste over dem, hvis konti er aktive. Hvordan finder du de inaktive id’er? Simpelt, ikke?

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 ]

Og hvad hvis du, som det sker i en mere realistisk setting, skal arbejde med en række objekter i stedet for almindelige primitiver? Nå, Lodash har en fin differenceBy() metode til dette!

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' } ]

Pænt, ikke?!

Ligesom forskel er der andre metoder i Lodash til almindelige sætoperationer: union, kryds osv.

Udfladning af arrays

Behovet for at udjævne arrays opstår ret ofte. Et tilfælde er, at du har modtaget et API-svar og skal anvende nogle map() og filter()-kombinationer på en kompleks liste af indlejrede objekter/arrays for at plukke ud f.eks. bruger-id’er, og nu står du tilbage med arrays af arrays. Her er et kodestykke, der viser denne 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' },
  ],
};

// 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);

Kan du gætte, hvordan postPaidUserIds ser ud nu? Tip: det er ulækkert!

[
  [],
  [
    { userId: 3, date: '2021-08-08', amount: 30, type: 'postpaid' },
    { userId: 4, date: '2021-06-06', amount: 330, type: 'postpaid' }
  ]
]

Nu, hvis du er en fornuftig person, ønsker du ikke at skrive brugerdefineret logik for at udtrække rækkefølgeobjekterne og lægge dem pænt ud i en række inde i et array. Bare brug flatten() metoden og nyd druerne:

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' }
]
*/

Bemærk, at flatten() kun går et niveau dybt. Det vil sige, hvis dine objekter sidder fast to, tre eller flere niveauer dybt, flatten() vil de skuffe dig. I disse tilfælde har Lodash metoden flattenDeep(), men vær advaret om, at anvendelse af denne metode på meget store strukturer kan bremse tingene (da bag kulisserne er der en rekursiv operation på arbejde).

  Bedste angrebsoverfladeovervågning for at kende din sikkerhedsrisikoeksponering

Er objektet/arrayet tomt?

Takket være, hvordan “falske” værdier og typer fungerer i JavaScript, resulterer noget så simpelt som at tjekke for tomhed nogle gange i eksistentiel frygt.

Hvordan kontrollerer du, om et array er tomt? Du kan kontrollere, om dens længde er 0 eller ej. Hvordan kontrollerer du nu, om et objekt er tomt? Nå…vent et øjeblik! Det er her, den urolige følelse sætter ind, og de JavaScript-eksempler, der indeholder ting som [] == falsk og {} == falsk begynder at kredse om vores hoveder. Når de er under pres for at levere en funktion, er landminer som disse det sidste, du har brug for – de vil gøre din kode svær at forstå, og de vil introducere usikkerhed i din testsuite.

Arbejder med manglende data

I den virkelige verden lytter data til os; uanset hvor gerne vi ønsker det, er det sjældent strømlinet og fornuftigt. Et typisk eksempel er manglende null-objekter/arrays i en stor datastruktur modtaget som API-svar.

Antag, at vi modtog følgende objekt som et API-svar:

const apiResponse = {
  id: 33467,
  paymentRefernce: 'AEE3356T68',
  // `order` object missing
  processedAt: `2021-10-10 00:00:00`,
};

Som vist får vi generelt et ordreobjekt i svaret fra API’et, men det er ikke altid tilfældet. Så hvad nu hvis vi har noget kode, der er afhængig af dette objekt? En måde ville være at kode defensivt, men afhængigt af hvor indlejret ordreobjektet er, ville vi snart skrive meget grim kode, hvis vi ønsker at undgå runtime fejl:

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
  );
}

🤢🤢 Ja, meget grimt at skrive, meget grimt at læse, meget grimt at vedligeholde, og så videre. Heldigvis har Lodash en ligetil måde at håndtere sådanne situationer på.

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

Der er også den fantastiske mulighed for at angive en standardværdi i stedet for at blive udefineret for manglende ting:

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

Jeg ved ikke med dig, men get() er en af ​​de ting, der bringer glædestårer frem i mine øjne. Det er ikke noget prangende. Der er ingen konsulteret syntaks eller muligheder for at huske, men se på mængden af ​​kollektiv lidelse, det kan lindre! 😇

Afstudsende

Hvis du ikke er bekendt, er debouncing et almindeligt tema i frontend-udvikling. Ideen er, at det nogle gange er fordelagtigt at starte en handling ikke med det samme, men efter nogen tid (generelt et par millisekunder). Hvad betyder det? Her er et eksempel.

Forestil dig et e-handelswebsted med en søgelinje (vel, enhver hjemmeside/webapp i disse dage!). For bedre UX ønsker vi ikke, at brugeren skal trykke på enter (eller endnu værre, trykke på “søg”-knappen) for at vise forslag/forhåndsvisninger baseret på deres søgeterm. Men det åbenlyse svar er lidt indlæst: hvis vi tilføjer en hændelseslytter til onChange() til søgelinjen og affyrer et API-kald for hvert tastetryk, ville vi have skabt et mareridt for vores backend; der ville være for mange unødvendige opkald (hvis der f.eks. søges efter “white carpet brush”, vil der være i alt 18 anmodninger!), og næsten alle disse vil være irrelevante, fordi brugerens input ikke er færdig.

Svaret ligger i debouncing, og ideen er denne: send ikke et API-kald, så snart teksten ændres. Vent et stykke tid (f.eks. 200 millisekunder), og hvis der på det tidspunkt er endnu et tastetryk, annuller den tidligere tidstælling og start igen at vente. Som følge heraf er det kun, når brugeren holder pause (enten fordi de tænker, eller fordi de er færdige, og de forventer noget svar), at vi sender en API-anmodning til backend.

Den overordnede strategi, jeg beskrev, er kompliceret, og jeg vil ikke dykke ned i synkroniseringen af ​​timerstyring og annullering; dog er selve debouncing-processen meget enkel, hvis du bruger 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

Hvis du tænker setTimeout() ville jeg have gjort det samme job, ja, der er mere! Lodashs debounce kommer med mange kraftfulde funktioner; for eksempel vil du måske sikre dig, at afvisningen ikke er ubestemt. Det vil sige, at selvom der er et tastetryk, hver gang funktionen er ved at starte (og dermed annullere den overordnede proces), vil du måske sikre dig, at API-kaldet alligevel foretages efter f.eks. to sekunder. Til dette har Lodash debounce() muligheden maxWait:

const debouncedFetchDogBreeds = _.debounce(fetchDogBreeds, 150, { maxWait: 2000 }); // debounce for 250ms, but send the API request after 2 seconds anyway

Tjek den officielle dokumenter for et dybere dyk. De er fulde af supervigtige ting!

  Hvad er 7DS Grand Cross Secret Box-koderne?

Fjern værdier fra et array

Jeg ved ikke med dig, men jeg hader at skrive kode til at fjerne elementer fra et array. Først skal jeg hente varens indeks, kontrollere om indekset rent faktisk er gyldigt og i så fald kalde splice() metoden, og så videre. Jeg kan aldrig huske syntaksen og har derfor brug for at slå tingene op hele tiden, og til sidst sidder jeg tilbage med den nagende følelse af, at jeg har ladet en eller anden dum fejl snige sig ind.

const greetings = ['hello', 'hi', 'hey', 'wave', 'hi'];
_.pull(greetings, 'wave', 'hi');
console.log(greetings);
// [ 'hello', 'hey' ]

Bemærk venligst to ting:

  • Det originale array blev ændret i processen.
  • Metoden pull() fjerner alle forekomster, selvom der er dubletter.
  • Der er en anden relateret metode kaldet pullAll(), der accepterer et array som den anden parameter, hvilket gør det nemmere at fjerne flere elementer på én gang. Indrømmet, at vi bare kunne bruge pull() med en spread-operator, men husk at Lodash kom på et tidspunkt, hvor spread-operatoren ikke engang var et forslag på sproget!

    const greetings2 = ['hello', 'hi', 'hey', 'wave', 'hi'];
    _.pullAll(greetings2, ['wave', 'hi']);
    console.log(greetings2);
    // [ 'hello', 'hey' ]

    Sidste indeks for et element

    JavsScripts native indexOf() metode er cool, undtagen når du er interesseret i at scanne arrayet fra den modsatte retning! Og endnu en gang, ja, du kunne bare skrive en dekrementerende løkke og finde elementet, men hvorfor ikke bruge en meget mere elegant teknik?

    Her er en hurtig Lodash-løsning ved hjælp af lastIndexOf()-metoden:

    const integers = [2, 4, 1, 6, -1, 10, 3, -1, 7];
    const index = _.lastIndexOf(integers, -1);
    console.log(index); // 7

    Desværre er der ingen variant af denne metode, hvor vi kan slå komplekse objekter op eller endda videregive en brugerdefineret opslagsfunktion.

    Lynlås. Pak ud!

    Medmindre du har arbejdet i Python, er zip/unzip et værktøj, du måske aldrig bemærker eller forestiller dig i hele din karriere som JavaScript-udvikler. Og måske af en god grund: der er sjældent den form for desperat behov for zip/unzip, som der er for filter() osv. Det er dog et af de bedst mindre kendte værktøjer, der findes og kan hjælpe dig med at skabe kortfattet kode i nogle situationer .

    I modsætning til hvad det lyder som, har zip/unzip intet at gøre med kompression. I stedet er det en grupperingsoperation, hvor arrays af samme længde kan konverteres til et enkelt array af arrays med elementer på samme position pakket sammen (zip()) og tilbage (unzip()). Ja, jeg ved det, det bliver tåget at prøve at nøjes med ord, så lad os se på noget kode:

    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' ] ]

    De oprindelige tre arrays blev konverteret til en enkelt med kun to arrays. Og hver af disse nye arrays repræsenterer et enkelt dyr med alt på ét sted. Så indekset 0 fortæller os, hvilken type dyr det er, indeks 1 fortæller os dets størrelse, og indeks 2 fortæller os dets vægt. Som et resultat er dataene nu nemmere at arbejde med. Når du har anvendt de operationer, du skal bruge på dataene, kan du bryde dem op igen ved at bruge unzip() og sende dem tilbage til den oprindelige kilde:

    const animalData = _.unzip(groupedAnimals);
    console.log(animalData);
    // [ [ 'duck', 'sheep' ], [ 'small', 'large' ], [ 'less', 'more' ] ]

    Zip/unzip-værktøjet er ikke noget, der vil ændre dit liv fra den ene dag til den anden, men det vil ændre dit liv en dag!

    Konklusion 👨‍🏫

    (Jeg har lagt al den kildekode, der er brugt i denne artikel her for at du kan prøve direkte fra browseren!)

    Lodashen dokumenter er propfyldt med eksempler og funktioner, der bare vil blæse dit sind. I en tid, hvor masochisme ser ud til at være stigende i JS-økosystemet, er Lodash som et frisk pust, og jeg anbefaler stærkt, at du bruger dette bibliotek i dine projekter!