Zpracování nulové a nedefinované v JavaScriptu

Jedním aspektem vývoje JavaScriptu, s nímž mnoho vývojářů bojuje, je jednání s volitelnými hodnotami. Jaké jsou nejlepší strategie pro minimalizaci chyb způsobených hodnotami, které mohou být null, undefined nebo jinak neinicializovány za běhu?

Některé jazyky mají za těchto okolností zabudované možnosti. V některých staticky zadaných jazycích můžete říci, že null a undefined jsou nelegální hodnoty, a nechte svůj programovací jazyk při kompilaci hodit TypeError , ale ani v těchto jazycích to nemůže „zabránit běhu nulových vstupů do programu za běhu.

Abychom tento problém lépe zvládli, musíme pochopit, odkud mohou tyto hodnoty pocházet. Tady jsou některé z nejběžnějších zdrojů:

  • Vstup uživatele
  • Záznamy databáze / sítě
  • Neinicializovaný stav
  • Funkce, které mohou nevrátit nic

Když se zabýváte vstupem uživatele, je ověření první a nejlepší obrannou linií. Často se spoléhám na validátory schémat, které vám s touto prací pomohou. Podívejte se například na reakci -jsonschema-form.

Hydratační záznamy ze vstupu

Vždy předávám vstupy, které dostávám ze sítě, databáze nebo ze vstupu uživatele prostřednictvím hydratační funkce. Například použiji tvůrci akcí redux, kteří zvládnou

hodnoty pro hydrataci záznamů uživatelů:

const setUser = ({ name = "Anonymous", avatar = "anon.png" } = {}) => ({
type: setUser.type,
payload: {
name,
avatar
}
});
setUser.type = "userReducer/setUser";

Někdy budete muset zobrazit různé věci v závislosti na aktuálním stavu údajů. Pokud je možné zobrazit stránku před inicializací všech dat, můžete se v takové situaci ocitnout. Když například uživateli zobrazujete zůstatky na penězích, můžete před načtením dat omylem zobrazit zůstatek 0 $. Toto rozrušené uživatele jsem viděl několikrát. Můžete vytvořit vlastní datové typy, které generují různé výstupy na základě aktuálního stavu:

Výše uvedený kód je stavový stroj, který znemožňuje zobrazit neplatné stavy. Když poprvé vytvoříte zůstatek, nastaví se do stavu uninitialized. Pokud se pokusíte zobrazit zůstatek, když je stav uninitialized, vždy místo něj získáte zástupnou hodnotu („--„).

Chcete-li to změnit, musíte explicitně nastavit hodnotu voláním metody .set nebo setBalance zkratky jsme definovali pod továrnou createBalance.

Samotný stav je zapouzdřen tak, aby byl chráněn před vnějším rušením, aby se zajistilo, že jej ostatní funkce nebudou moci chytit a nastavit do neplatného stavu.

Poznámka: Pokud vás zajímá, proč místo čísel používáme řetězce, je to proto, že reprezentuji typy peněz s velké číselné řetězce se spoustou desetinných přesností, aby se zabránilo chybám zaokrouhlování a přesně reprezentovaly hodnoty transakcí kryptoměny, které mohou mít libovolnou významnou desetinnou přesnost.

Pokud Pokud používáte architekturu Redux nebo Redux, můžete deklarovat stavové stroje pomocí Redu x-DSM.

Vyvarujte se vytváření nulových a nedefinovaných hodnot

Ve svých vlastních funkcích se můžete vyhnout vytváření null nebo undefined hodnoty pro začátek. Existuje několik způsobů, jak to udělat, zabudovaných do JavaScriptu, které se vám vybaví. Viz níže.

Vyhněte se null

Nikdy v jazyce JavaScript výslovně nevytvářím hodnoty null, protože jsem nikdy neviděl smysl mít dva různé primitivní hodnoty, které v podstatě znamenají „tato hodnota neexistuje.“

Od roku 2015 podporuje JavaScript výchozí hodnoty, které se vyplní, když nezadáte hodnotu pro daný argument nebo vlastnost. Tato výchozí nastavení nefungují pro hodnoty null. Podle mých zkušeností je to obvykle chyba. Abyste se této pasti vyhnuli, nepoužívejte null v JavaScriptu.

Pokud chcete speciální případy pro neinicializované nebo prázdné hodnoty, stavové automaty jsou lepší sázkou. Viz výše.

Nové funkce JavaScriptu

Existuje několik funkcí, které vám mohou pomoci při řešení null nebo undefined hodnoty. Oba jsou v době psaní tohoto článku návrhy 3. etapy, ale pokud čtete z budoucnosti, můžete je použít.

Od tohoto psaní je volitelným zřetězením návrh 3. etapy. Funguje to takto:

const foo = {};
// console.log(foo.bar.baz); // throws error
console.log(foo.bar?.baz) // undefined

Nullish Coalescing Operator

Do specifikace je také přidán návrh fáze 3, „nullish coalescing operator „Je v podstatě fantazijní způsob, jak říci„ operátor záložní hodnoty “. Pokud je hodnota vlevo undefined nebo null, vyhodnotí se to hodnota vpravo.Funguje to takto:

Asynchronní buď s přísliby

Pokud se funkce nemusí vrátit s hodnotou, může být dobrý nápad ji zabalit do Either. Ve funkčním programování je Either monad speciální abstraktní datový typ, který umožňuje připojit dvě různé cesty kódu: cestu úspěchu nebo cestu selhání. JavaScript má integrovaný asynchronní datový typ Monad-ish s názvem Promise. Můžete jej použít k deklarativní větvení chyb pro nedefinované hodnoty:

Pokud chcete, můžete napsat jeho synchronní verzi, ale moc ji nepotřebuji. Nechám to jako cvičení pro vás. Pokud máte dobré základy ve funktorech a monadách, bude proces jednodušší. Pokud to zní hrozivě, nedělejte si s tím starosti. Stačí použít sliby. Jsou integrovány a většinou fungují dobře.

Pole pro Maybes

Pole implementují metodu map, která trvá funkce, která se použije na každý prvek pole. Pokud je pole prázdné, funkce nebude nikdy volána. Jinými slovy, pole v JavaScriptu mohou vyplnit roli Maybes z jazyků, jako je Haskell.

Co je možná?

Možná je speciální abstraktní datový typ, který zapouzdřuje volitelnou hodnotu . Datový typ má dvě podoby:

  • Jen – Možná, že obsahuje hodnotu
  • Nic – Možná – bez hodnoty

Zde je podstata myšlenky:

Toto je pouze příklad k prokázání koncepce. Kolem maybes můžete vytvořit celou knihovnu užitečných funkcí a implementovat další operace, jako jsou flatMap a flat (např. Vyhnout se Just(Just(value)) při vytváření více funkcí Možná se vrací). Ale JavaScript již má datový typ, který implementuje mnoho z těchto funkcí ihned po vybalení, takže místo toho obvykle sáhnu: Pole.

Pokud chcete vytvořit funkci, která může nebo nemusí přinést výsledek (zejména pokud může být více než jeden výsledek), můžete mít skvělý případ pro vrácení pole.

Zjistil jsem, že map nebude vyvolán na prázdném seznamu, což je velmi užitečné pro zabránění hodnotám null a undefined, ale pamatujte, že pokud pole obsahuje null a undefined hodnoty, zavolá funkci s těmito hodnotami, takže pokud funkce, kterou právě běžíte, může vyprodukovat null nebo undefined, budete je muset odfiltrovat ze svého vráceného pole, jak je uvedeno výše. To by mohlo mít vliv na změnu délky kolekce.

V Haskellu existuje funkce maybe, která (jako ) použije funkci na hodnotu. Ale hodnota je volitelná a zapouzdřená v Maybe. Pomocí datového typu Array JavaScriptu můžeme dělat v podstatě totéž:

maybe má záložní hodnotu , pak funkce mapující pole možná, pak pole možná (pole obsahující jednu hodnotu nebo nic) a vrátí buď výsledek použití funkce na obsah pole, nebo záložní hodnotu, pokud je pole prázdný.

Pro větší pohodlí jsem také definoval funkci toMaybeArray a vytvořil funkci maybe pro tuto demonstraci je to nejzřejmější.

Pokud byste chtěli něco podobného udělat v produkčním kódu, vytvořil jsem pro testování jednodušší open source knihovnu. Říká se tomu Maybearray. Výhodou Maybearray oproti jiným JavaScriptům Možná, že knihovny jsou, že k zobrazení hodnot používá nativní pole JavaScriptu, takže jim nemusíte dávat žádné speciální zacházení ani dělat nic zvláštního pro převod tam a zpět. Když se při ladění setkáte s poli Možná, nemusíte se ptát: „co je to za divný typ ?!“ Je to jen pole s hodnotou nebo prázdné pole a už jste je viděli milionkrát.

Další kroky

Na EricElliottJS.com je mnohem více obsahu, včetně spousty videí, cvičení, zaznamenaných screencastů a rychlých tipů. Pokud nejste členem, nyní je skvělý čas podívat se, co vám chybí!

Začněte svou bezplatnou lekci na EricElliottJS.com

Write a Comment

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *