6 funkcji JavaScript, które powinieneś znać

Opublikowany: 2020-09-24

Nieco ponad rok temu rozmawialiśmy o 5 „nowych” funkcjach JavaScript, które powinieneś znać, aby wygodnie rozwijać się w Gutenbergu. Tam dowiedzieliśmy się, czym jest destrukturyzacja obiektów i tablic, jak tworzyć funkcje strzałek, jakie są operatory rozproszenia i reszty i tak dalej. Masz szczęście, JavaScript wciąż ma wiele funkcji, które po zapoznaniu się z nimi pomogą Ci napisać bardziej zrozumiały i zwięzły kod.

Dzisiaj pokażę Wam sześć naprawdę fajnych funkcji JavaScript. Operatory, zmienne zakresy, obietnice, funkcje asynchroniczne… czy jesteś gotowy, aby nauczyć się ich wszystkich?

#1 Opcjonalne łączenie łańcuchów w JavaScript z operatorem ?.

Opcjonalny operator łączenia w łańcuch umożliwia uproszczony dostęp do atrybutów obiektu, gdy istnieje szansa, że ​​jest on undefined lub null . Załóżmy na przykład, że masz obiekt podobny do następującego:

 const toni = { name: 'Antonio', details: { age: 35, }, };

Aby uzyskać dostęp do age toni , musisz najpierw uzyskać dostęp do atrybutu details , a następnie age :

 function getAge( person ) { return person.details.age; }

Problem, który mamy w poprzedniej funkcji i jestem pewien, że nie jest to dla ciebie nic nowego, polega na tym, że właściwości, których oczekujemy od person , nie zawsze istnieją. Oznacza to, że jeśli person lub person.detailsundefined , powyższa funkcja wywoła błąd typu:

 getAge( toni ); // 35 getAge( {} ); // Uncaught TypeError: person.details is undefined

Zwykle rozwiązujemy ten problem, dodając kilka bezpiecznych osłon:

 function getAge( person ) { if ( ! person ) { return; } if ( ! person.details ) { return; } return person.details.age; } getAge( toni ); // 35 getAge( {} ); // undefined

które wyraźnie to naprawić. Niestety, wynikowa funkcja jest bardziej złożona i zawiera dużo zaszumionego kodu, który odwraca naszą uwagę od rzeczy, które naprawdę mają znaczenie. Aby wrócić na właściwe tory i naprawić rozwiązanie w prostszy sposób, wystarczy użyć opcjonalnego operatora łańcucha ?. :

 function getAge( person ) { return person?.details?.age; } getAge( toni ); // 35 getAge( {} ); // undefined

Zasadniczo ten operator pozwala nam uzyskać dostęp do każdej właściwości, o ile nie jest ona undefined lub null . Gdy tylko wykryje, że próbujemy uzyskać dostęp do właściwości nieistniejącego obiektu, zwraca undefined .

# 2 Zerowy operator łączenia ( ?? )

W JavaScript bardzo łatwo jest ustawić domyślną wartość zmiennej za pomocą tego operatora: || , prawidłowy? Zło! Wszyscy to zrobiliśmy, ale może to spowodować nieoczekiwane skutki uboczne, jeśli nie będziesz ostrożny…

Załóżmy na przykład, że w naszym sklepie Redux mamy selektor, który pozwala nam pobrać wartość ustawioną przez użytkownika. Jeśli użytkownik nie podał jeszcze wartości (tzn. wartość jest undefined ), zwracamy wartość domyślną za pomocą || :

 function getValue( state ) { return state.value || 5; }

Zobaczmy teraz kilka przykładów tego, co otrzymalibyśmy z poprzednią funkcją po ustawieniu przez użytkownika takiej lub innej wartości:

 // No setValue( x )... getValue(); // 5 setValue( 2 ); getValue(); // 2 setValue( 1 ); getValue(); // 1 setValue( 0 ); getValue(); // 5

Ups! Wszystko działało dobrze, dopóki nie dotarliśmy do ostatniej sprawy! Najwyraźniej, jeśli użytkownik ustawi wartość na 0 , wynikiem funkcji będzie 5 . Czemu? Cóż, uzasadnienie jest dość niejasne: x||y zwraca y wtedy i tylko wtedy, gdy x jest wartością „fałszywą”. Zwykle działa to dobrze, ponieważ undefined jest fałszywą wartością. Ale tak samo są na przykład false lub 0 .

W rzeczywistości chcieliśmy ustawić wartość default tylko wtedy, gdy jej nie ma. Możemy więc dodać bezpieczną osłonę, aby sprawdzić, czy istnieje wartość, czy nie:

 function getValue( state ) { if ( undefined === state.value ) return 5; return state.value; }

i możemy nawet napisać go za pomocą operatora trójargumentowego, jeśli mamy ochotę:

 function getValue( state ) { return undefined === state.value ? 5 : state.value; }

ale po raz kolejny oba rozwiązania niepotrzebnie komplikują kod. Aby przypisać domyślną wartość do zmiennej, musimy użyć zerowego operatora koalescencyjnego ?? , który zwraca prawą część wtedy i tylko wtedy, gdy lewa część ma null lub undefined :

 function getValue( state ) { return state.value ?? 5; }

i, niespodzianka!, wynik jest dokładnie taki, jak chcieliśmy:

 // No setValue( x )... getValue(); // 5 setValue( 2 ); getValue(); // 2 setValue( 1 ); getValue(); // 1 setValue( 0 ); getValue(); // 0

A tak przy okazji, możesz użyć tego operatora w połączeniu z przypisaniem. Na przykład to:

 value = value ?? 5;

jest równoważne z tym:

 value ??= 5;

#3 Obietnice i funkcje asynchroniczne

Promises to mechanizm zaimplementowany w JavaScript, który pozwala nam uprościć nasz kod źródłowy podczas pracy z operacjami asynchronicznymi, czyli operacjami, których wyniki nie są od razu dostępne. Na przykład, jeśli chcemy pobrać dane z naszego serwera, jasne jest, że odpowiedź nie będzie natychmiastowa, ponieważ musimy poczekać, aż serwer otrzyma żądanie, przetworzy je i odeśle nam odpowiedź.

W starszych wersjach i bibliotekach JavaScript (na przykład jQuery) używaliśmy do implementacji tego za pomocą wywołań zwrotnych. Pomysł był dość prosty: wraz z samym żądaniem zdefiniować funkcję (callback), która powinna zostać wywołana, gdy odpowiedź będzie dostępna. W ten sposób po zakończeniu operacji asynchronicznej (czyli pobierania danych z serwera) biblioteka wywoła funkcję i nasza logika zostanie wznowiona:

 jQuery.ajax( { url: 'https://server.com/wp-json/wp/users/1', success: ( user ) => { console.log( user ); }, } );

Jeśli uruchamiamy tylko pojedyncze, wyizolowane żądanie, to rozwiązanie jest dość eleganckie i wygodne. Ale jak tylko musimy wykonać więcej żądań, rzeczy szybko się brudzą. Na przykład, jeśli chcemy zażądać dwóch różnych użytkowników, musielibyśmy zagnieździć wywołania zwrotne:

 jQuery.ajax( { url: 'https://server.com/wp-json/wp/v2/users/1', success: ( user1 ) => { jQuery.ajax( { url: 'https://server.com/wp-json/wp/v2/users/2', success: ( user2 ) => { console.log( user1, user2 ); }, } ); }, } );

Rozwiązaniem tego problemu są obietnice: jeśli uzyskanie określonego wyniku nie jest natychmiastowe (tak jak na przykład pobranie czegoś z serwera), możemy od razu zwrócić obietnicę JavaScript. Ten obiekt jest opakowaniem rzeczywistej wartości i oznacza „obietnicę”, że wspomniana wartość będzie dostępna w pewnym momencie w przyszłości.

Na przykład, gdybyśmy mieli przepisać nasz pierwszy fragment za pomocą obietnic, wyglądałoby to tak:

 const promise = wp.apiFetch( { url: 'https://server.com/wp-json/wp/v2/users/1', } ); promise.then( ( user ) => console.log( user ) );

Jak widać, wp.apiFetch musi pobrać użytkownika 1 z serwera, ale od razu daje wynik. Rezultatem nie jest jednak sam użytkownik, ale obietnica, która zostanie zrealizowana dla użytkownika po zakończeniu żądań. Dlatego wszystko, co musimy zrobić, to napisać wywołanie zwrotne, które przetworzy odpowiedź na obietnicę, gdy zostanie rozwiązana.

Teraz możesz pomyśleć, że nie jest to takie trudne z tego, co mieliśmy wcześniej, prawda? W końcu nadal używamy wywołań zwrotnych… ale możesz zobaczyć, jak przydatne jest to, gdy zaczniemy łączyć wiele żądań:

 const promise1 = wp.apiFetch( { url: 'https://server.com/wp-json/wp/v2/users/1', } ); const promise2 = wp.apiFetch( { url: 'https://server.com/wp-json/wp/v2/users/2', } ); Promise.all( [ promise1, promise2 ] ).then( ( [ user1, user2 ] ) => console.log( user1, user2 ); );

Korzystając z obietnic, byliśmy w stanie uruchomić dwa równoległe żądania, aby pobrać użytkowników 1 i 2, i użyć Promise.all , aby poczekać, aż obie obietnice zostaną rozwiązane. Brak kodu spaghetti z zagnieżdżonymi wywołaniami zwrotnymi.

Cóż, wspaniałe obietnice dopiero nadejdą. Możemy użyć trochę cukru syntaktycznego, aby pracować z obietnicami JavaScript i pisać asynchroniczny kod, który wygląda, no cóż, synchronicznie. Wszystko, co musisz zrobić, to zdefiniować funkcję asynchroniczną za pomocą słowa kluczowego async i nagle wszystko staje się o wiele łatwiejsze:

 async function logTwoUsers( id1, id2 ) { const user1 = await wp.apiFetch( { url: '…' + id1 } ); const user2 = await wp.apiFetch( { url: '…' + id2 } ); console.log( user1, user2 ); }

Za każdym razem, gdy wywołujesz operację asynchroniczną w ramach funkcji asynchronicznej, możesz poczekać na jej wynik za pomocą słowa kluczowego await . Jedyną rzeczą, o której należy pamiętać, jest to, że kiedy definiujesz funkcję async , jej wynikiem zawsze będzie obietnica:

 async function getNumberFive() { return 5; } const p = getNumberFive(); // a promise p.then( console.log ); // prints "5"

#4 Zmienny zakres przy użyciu let i const

Jak zapewne już wiesz, możesz teraz deklarować zmienne za pomocą słów kluczowych let i const . Pierwsza definiuje zmienną, a druga definiuje stałą:

 let x = 1; console.log( x ); // 1 x = 2; console.log( x ); // 2 const y = 1; console.log( y ); // 1 y = 2; // Uncaught TypeError: invalid assignment to const 'y' console.log( y ); // 1

Możesz pokusić się o stwierdzenie, że let i var to to samo, ponieważ oba słowa kluczowe pozwalają nam zadeklarować zmienną niestałą. Ale jest między nimi zasadnicza różnica: ich zakres. W przypadku let i const zakresem zmiennej jest blok, w którym jest zdefiniowana. W var jest to cała funkcja.

 function fn() { if ( true ) { var x = 1; let y = 2; const z = 3; }//end if console.log( x ); // 1 console.log( y ); // Uncaught ReferenceError: y is not defined console.log( z ); // Uncaught ReferenceError: z is not defined }

# 5 Transformacja danych przy użyciu JSON.parse

Funkcja JSON.parse analizuje ciąg znaków JSON i buduje obiekt JavaScript. Na przykład:

 const x = JSON.parse( '{"x":1,"a":[1,2,3]}' ); // Object { x: 1, a: [ 1, 2, 3 ] }

Większość ludzi nie wie o tym, że wspiera drugi argument zwany reviver . Ten parametr jest funkcją, która będzie wykonywana dla każdego analizowanego elementu, umożliwiając manipulowanie wartością według własnego uznania. Na przykład wyobraź sobie ciąg JSON podobny do następującego:

 const json = '{"name":"David","birthday":"1985-12-01T10:00:00.000Z"}';

Jeśli użyjemy JSON.parse bez zmian, wygeneruje obiekt z dwoma atrybutami ciągu: name i birthday . Ale jeśli udostępnimy funkcję reviver do JSON.parse , możemy upewnić się, że birthday są analizowane jako Date :

 const user = JSON.parse( json, ( key, value ) => 'birthday' === key ? new Date( value ) : value )

# 6 Separator liczbowy w kodzie źródłowym za pomocą znaku Undesrcore ( _ )

Naszą ostatnią dzisiejszą wskazówką jest separator liczbowy. Istnieje propozycja (obecnie na etapie 4), która umożliwia pisanie liczb w sposób ułatwiający ludziom zrozumienie. Na przykład, czy naprawdę możesz powiedzieć, jak duże są poniższe liczby?

 10000000000 2189719.25

Gdybyśmy tylko mogli użyć separatora tysięcy, byłoby to znacznie łatwiejsze do zinterpretowania! I właśnie to możemy zrobić za pomocą podkreślenia _ :

 10_000_000_000 2_189_719.25

Streszczenie

Możliwe jest napisanie lepszego kodu JavaScript, jeśli przyzwyczaisz się do wszystkich nowych narzędzi i funkcji zawartych w JavaScript. Dziś widzieliśmy kilka przykładów tego, co jest możliwe dzięki temu językowi programowania. Mam nadzieję, że nauczyłeś się czegoś nowego i jeśli Ci się spodobało, nie zapomnij podzielić się tym z kolegami. Do zobaczenia wkrótce!

Polecane zdjęcie Sama Dana Truonga na Unsplash.