Et aspekt af JavaScript-udvikling, som mange udviklere kæmper med, er at beskæftige sig med valgfri værdier. Hvad er de bedste strategier for at minimere fejl forårsaget af værdier, der kunne være null
, undefined
eller på anden måde ikke-initialiseres ved kørsel?
Nogle sprog har indbyggede overkommelser under disse omstændigheder. På nogle statisk typede sprog kan du sige, at null
og undefined
er ulovlige værdier, og lad dit programmeringssprog kaste et TypeError på kompileringstidspunktet , men selv på disse sprog kan det ikke forhindre, at nul-input strømmer ind i programmet under kørsel.
For at få et bedre greb om dette problem, er vi nødt til at forstå, hvor disse værdier kan komme fra. Her er nogle af de mest almindelige kilder:
- Brugerinput
- Database / netværksregistreringer
- Ikke-initialiseret tilstand
- Funktioner, der kunne returner intet
Når du har at gøre med brugerinput, er validering den første og bedste forsvarslinje. Jeg stoler ofte på skemavalidatorer for at hjælpe med det job. Se f.eks. -jsonschema-form.
Hydrating Records from Input
Jeg sender altid input, som jeg modtager fra netværket, databasen eller brugerinput via en hydratiseringsfunktion. For eksempel bruger jeg redux action skabere, der kan håndtere
værdier for at hydrere brugeroptegnelser:
const setUser = ({ name = "Anonymous", avatar = "anon.png" } = {}) => ({
type: setUser.type,
payload: {
name,
avatar
}
});
setUser.type = "userReducer/setUser";
Nogle gange skal du vise forskellige ting afhængigt af den aktuelle tilstand af dataene. Hvis det er muligt at vise en side, før alle data initialiseres, kan du komme i den situation. For eksempel, når du viser pengesaldi til en bruger, kan du ved et uheld vise en saldo på $ 0, før dataene indlæses. Jeg har set dette forstyrre brugerne flere gange. Du kan oprette brugerdefinerede datatyper, der genererer forskellige output baseret på den aktuelle tilstand:
Koden ovenfor er en tilstandsmaskine, der gør det umuligt at vise ugyldige tilstande. Når du først opretter balancen, indstilles den til en uninitialized
-tilstand. Hvis du prøver at vise en balance, mens tilstanden er uninitialized
, får du altid en pladsholderværdi (“--
“) i stedet.
For at ændre det skal du udtrykkeligt indstille en værdi ved at kalde .set
-metoden eller setBalance
genvej definerede vi nedenfor createBalance
fabrikken.
Selve staten er indkapslet for at beskytte den mod interferens udefra for at sikre, at andre funktioner ikke kan få fat i den og indstille den til en ugyldig tilstand.
Bemærk: Hvis du undrer dig over, hvorfor vi bruger strenge i stedet for tal til dette, er det fordi jeg repræsenterer pengetyper med store talstrenge med masser af decimalpræcision for at undgå afrundingsfejl og nøjagtigt repræsenterer værdier for kryptokurrency-transaktioner, som kan have vilkårlig betydelig decimalpræcision.
Hvis du ‘ ved hjælp af Redux eller Redux-arkitektur kan du erklære tilstandsmaskiner med Redu x-DSM.
Undgå at oprette null og udefinerede værdier
I dine egne funktioner kan du undgå at oprette null
eller undefined
værdier til at begynde med. Der er et par måder at gøre det indbygget i JavaScript, der kommer i tankerne. Se nedenfor.
Undgå null
Jeg opretter aldrig eksplicit null
værdier i JavaScript, fordi jeg aldrig rigtig så pointen med at have to forskellige primitive værdier, der i det væsentlige betyder “denne værdi findes ikke.”
Siden 2015 har JavaScript understøttet standardværdier, der udfyldes, når du ikke angiver en værdi for det pågældende argument eller ejendom. Disse standardværdier virker ikke for null
-værdier. Efter min erfaring er det normalt en fejl. For at undgå denne fælde skal du ikke bruge null
i JavaScript.
Hvis du vil have specielle tilfælde til ikke-initialiserede eller tomme værdier, er tilstandsmaskiner et bedre valg. Se ovenfor.
Nye JavaScript-funktioner
Der er et par funktioner, der kan hjælpe dig med at håndtere null
eller undefined
værdier. Begge er trin 3-forslag på tidspunktet for denne skrivning, men hvis du læser fra fremtiden, kan du muligvis bruge dem.
Fra dette tidspunkt er valgfri sammenkædning et trin 3-forslag. Det fungerer således:
const foo = {};
// console.log(foo.bar.baz); // throws error
console.log(foo.bar?.baz) // undefined
Nullish Coalescing Operator
Også et trin 3-forslag, der skal tilføjes til specifikationen, “nullish coalescing operator ”Er grundlæggende en fancy måde at sige” operator for tilbagevendende værdi “. Hvis værdien til venstre er undefined
eller null
, evalueres den til værdien til højre.Det fungerer således:
Asynkron enten med løfter
Hvis en funktion muligvis ikke vender tilbage med en værdi, kan det være en god ide at pakke den ind i en af dem. I funktionel programmering er Enten monaden en speciel abstrakt datatype, der giver dig mulighed for at vedhæfte to forskellige kodestier: en successti eller en fejlsti. JavaScript har en indbygget asynkron enten monadisk datatype kaldet Promise. Du kan bruge den til at udføre deklarative forgreninger til udefinerede værdier:
Du kan skrive en synkron version af det, hvis du vil, men jeg har ikke haft brug for det meget. Jeg vil lade det være som en øvelse for dig. Hvis du har en god forankring i funktorer og monader, bliver processen lettere. Hvis det lyder truende, skal du ikke bekymre dig om det. Brug bare løfter. De er indbyggede, og de fungerer fint det meste af tiden.
Arrays for Maybes
Arrays implementerer en map
metode, der tager en funktion, der anvendes på hvert element i arrayet. Hvis matrixen er tom, kaldes funktionen aldrig. Med andre ord kan Arrays i JavaScript udfylde Maybes rolle fra sprog som Haskell.
Hvad er en måske?
A Måske er en speciel abstrakt datatype, der indkapsler en valgfri værdi . Datatypen har to former:
- Bare – A Måske der indeholder en værdi
- Intet – en måske uden værdi
Her er idéens kerne:
Dette er kun et eksempel på at demonstrere konceptet. Du kan opbygge et helt bibliotek med nyttige funktioner omkring maybes og implementere andre operationer som flatMap
og flat
(f.eks. For at undgå Just(Just(value))
når du komponerer flere måske-returnerende funktioner). Men JavaScript har allerede en datatype, der implementerer mange af disse funktioner out-of-the-box, så jeg når normalt frem til det i stedet: Arrayen.
Hvis du vil oprette en funktion, der kan eller muligvis ikke producerer et resultat (især hvis der kan være mere end et resultat), har du muligvis en god brugssag til at returnere en matrix.
Jeg finder det faktum, at map
kaldes ikke på en tom liste, der er meget nyttig til at undgå null
og undefined
værdier, men husk, hvis arrayet indeholder null
og undefined
værdier, det kalder funktionen med disse værdier, så hvis den funktion, du kører, kunne producere null
eller undefined
, skal du filtrere dem ud af dit returnerede array, som vist ovenfor. Det kan medføre, at længden af samlingen.
I Haskell er der en funktion maybe
der (som ) anvender en funktion til en værdi. Men værdien er valgfri og indkapslet i en Maybe
. Vi kan bruge JavaScript “s Array
datatype til stort set at gøre det samme:
maybe
tager en reserveværdi , derefter en funktion til at kortlægge måske arrayet, derefter et måske array (et array indeholdende en værdi eller intet), og returnerer enten resultatet af at anvende funktionen på arrayets indhold eller reserveværdien, hvis arrayet er tom.
For nemheds skyld har jeg også defineret en toMaybeArray
-funktion og curried funktionen maybe
for at gøre det mest åbenlyse for denne demonstration.
Hvis du gerne vil gøre noget som dette i produktionskoden, har jeg oprettet et enhedstestet open source-bibliotek for at gøre det lettere. Det hedder Maybearray. Fordelen ved Maybearray i forhold til andre JavaScript-biblioteker Måske er det, at det bruger native JavaScript-arrays til at repræsentere værdier, så du behøver ikke give dem nogen særlig behandling eller gøre noget særligt for at konvertere frem og tilbage. Når du støder på måske arrays i din fejlretning, behøver du ikke spørge, “hvad er denne underlige type ?!” Det er bare en matrix med en værdi eller en tom matrix, og du har set dem en million gange før.
Næste trin
Der er meget mere indhold på EricElliottJS.com, inklusive masser af videoer, øvelser, optagede screencasts og hurtige tip. Hvis du ikke er medlem, er det nu et godt tidspunkt at se, hvad du har savnet!