Miniatura artykułu

Destrukturyzacja w JavaScript

10 minut

Skopiuj link

Data publikacji: 9/3/2023, 11:41:23

Ostatnia aktualizacja: 4/1/2024

Destrukturyzacja, czyli co?

Destrukturyzacja to mechanizm, który istnieje nie tylko w JavaScript. Implementują go również inne języki programowania (np. Python i C#). Dzięki niemu można "wypakować" wartości z tablicy, lub obiektu bezpośrednio do zmiennych, a tym samym znacznie skrócić zapis i zwiększyć czytelność kodu.

Zamiast wielokrotnie odwoływać się najpierw do obiektu, a następnie do jego właściwości, możemy używać bezpośrednio właściwości, które wcześniej przypisaliśmy do zmiennych. Jest również kilka pułapek, na które trzeba uważać, ale o tym na samym końcu.

Podstawy

Jak wspomniałem destrukturyzacja dotyczy tablic (które w JavaScript są tak naprawdę obiektami) oraz obiektów. Na początek przyjrzymy się tym drugim.

W przykładzie powyżej utworzyłem trzy nowe zmienne (address, age, name) używając destrukturyzacji. Teraz mogę używać ich bezpośrednio - nie muszę odwoływać się najpierw do obiektu person.name lub person.age.

To teraz po kolei przeanalizujmy co tu się wydarzyło:

  1. użyłem słowa kluczowego const do zadeklarowania zmiennej (let, oraz var również zadziała).

  2. w nawiasach klamrowych (w przypadku tablic będą to nawiasy kwadratowe [ ]) wymieniłem po kolei właściwości obiektu na podstawie których chcę utworzyć zmienne. Ich nazwa musi odpowiadać tym w obiekcie person.

  3. ostatni krok to operator przypisania =. Bezpośrednio po nim umieściłem obiekt, który posiada te właściwości.

Składnia w przypadku tablic wygląda niemal identycznie. Szczegółowo opisuję ją w dalszej części artykułu przy okazji poznawania dodatkowych możliwości destrukturyzacji.

Referencja w destrukturyzacji

Przyjrzyjmy się kolejnemu przykładowi. Tym razem zastosujemy destrukturyzację bezpośrednio w parametrze funkcji. Składnia wygląda tu nieco inaczej - nie deklarujemy zmiennej, a jedynie wyciągamy wskazaną właściwość z obiektu.

Funkcja updateCity zmienia właściwość city obiekcie address, który znajduje się wewnątrz obiektu person przekazanego jako pierwszy argument. Bardzo ważną kwestią jest tutaj referencja. W przypadku wyciągnięcia za pomocą destrukturyzacji typu referencyjnego (np. obiektu lub tablicy) mamy do czynienia z oryginalnym obiektem, nie dochodzi do utworzenia kopii. W naszym przypadku wszystkie operacje (takie jak nadpisanie właściwości city) są dokonywane na obiekcie address i to on zostanie zmodyfikowany.

Inaczej kwestia wygląda w przypadku typów prostych. Przyjrzyjmy się funkcji updateAge. Tu również destrukturyzyjemy obiekt person, jednak age jest typem prostym. Mamy tu do czynienia z kopią wartości, a nie referencją do obiektu person. Zatem jakiekolwiek operacje są dokonywane na nowej, niepowiązanej z obiektem person wartości. Co za tym idzie, ta funkcja po prostu nie działa - obiekt person nie zostanie zmodyfikowany.

Wiązanie this

Co prawda destrukturyzacja metod zdarza się niezwykle rzadko, jednak warto wiedzieć jak zachowa się program w takiej sytuacji.

Jeżeli metoda używa wewnątrz słowa kluczowego this, to wywołanie jej w ten sposób spowoduje, że nie będzie ono wskazywać na obiekt, z którego pochodzi metoda. Powiązanie pomiędzy obiektem, a słowem this tworzy się dopiero w czasie działania aplikacji, dlatego kontekst wywołania metody ma spore znaczenie.

Rozwiązań tego problemu jest kilka:

  • możemy użyć metody bind do trwałego przypisania this do obiektu blogPost. Wymaga to jednak utworzenia dodatkowej zmiennej, która będzie przechowywać zbindowaną wersję metody.

  • podczas używania funkcji możesz stosować metody call lub apply w celu manualnego wskazania kontekstu this

Oczywiście rozwiązań jest znacznie więcej, ale te, które przedstawiłem stosuje się zdecydowanie najczęściej.

Jeżeli zdecydujesz się zdestrukturyzować metodę, to koniecznie sprawdź, czy wynik jej wywołania jest poprawny.

Wartości domyślne

Podczas destrukturyzowania tablicy lub obiektu możemy przypisać domyślne wartości do wyciąganych właściwości. Zobaczymy to na przykładzie tablicy.

Zapis wygląda tu niemal identycznie, jak podczas destrukturyzacji obiektu. Jedyna różnica, to nawiasy kwadratowe zamiast klamrowych.

Nowością jest tutaj dodanie operatora przypisania = wraz z domyślną wartością. Dokładnie ten sam zapis możemy zastosować w parametrach funkcji. Należy pamiętać, że domyślna wartość zostanie użyta tylko wtedy, gdy w miejscu parametru znajdzie się wartość undefined (nie zadziała to w przypadku null).

Z tego powodu w przykładzie poniżej mimo, że przypisałem domyślną do czwartego elementu, to nie zostanie ona zastosowana. Tak samo sytuacja wygląda w przypadku domyślnych wartości dla parametrów funkcji.

Domyślne wartości można stosować zarówno podczas destrukturyzacji obiektów jak i tablic, a wartość, która zostanie tam przypisana zależy tylko od Ciebie. W przykładzie powyżej domyślną wartością jest wywołanie funkcji. logMissingPerson wykona się tylko w momencie, kiedy wartością będzie undefined.

Kolizja nazw

Czasami może się okazać, że zmienna o takiej samej nazwie istnieje w danym kontekście. W takim przypadku najłatwiej jest zmienić nazwę destrukturyzowanej właściwości i uniknąć kolizji nazw.

Sam zapis nie jest skomplikowany - nadal używamy nazwy właściwości takiej, jak w obiekcie person, jednak zaraz po niej stosujemy dwukropek :, a tuż po nim nadajemy nową nazwę.

Ta zmiana nie wpływa na obiekt person, a jedynie tworzy nową zmiennej o tej nazwie. Zatem oryginalny obiekt pozostaje niezmieniony.

Zmiana nazwy może być połączona z wartością domyślną, chociaż sam zapis nie jest czytelny na pierwszy rzut oka. Podobnie jak poprzednio najpierw za pomocą dwukropka zmieniamy nazwę, a następnie z użyciem operatora przypisania = nadajemy wartość domyślną.

Operator rest

Podczas destrukturyzacji możemy posłużyć się operatorem rest ... w celu "zebrania" wszystkich pozostałych wartości. Operator ten zawsze musi znaleźć się na samym końcu (podobnie jak w parametrach funkcji).

Zastosowałem tu podobny zapis, co poprzednio, jednak na końcu dodałem ...personWithoutName (nazwa jest tutaj dowolna i zależy tylko od Ciebie). Pod tą wartością znajdują się wszystkie właściwości z obiektu person, które nie zostały wcześniej zdestrukturyzowane i przypisane do zmiennych.

Ponieważ wcześniej wyciągnęliśmy do zmiennej jedynie name, to do personWithoutName trafił cały obiekt, poza tą jedną właściwością. Nic jednak nie stoi na przeszkodzie, żeby wyciągnąć wcześniej więcej niż jedną rzecz, wtedy operator rest zbierze pozostałe właściwości.

Zaawansowana destrukturyzacja

Wiesz już prawie wszystko na temat destrukturyzacji. Zostały nam jeszcze do poruszenia dwie kwestie - zagnieżdżona destrukturyzacja oraz zastosowanie przecinka , w celu pominięcia niektórych wartości.

Zamiast poznawać je po kolei, tak jak inne zagadnienia, posłużymy się tym razem bardziej zaawansowanym przykładem i zastosujemy wszystkie poznane do tej pory techniki, a przy okazji wprowadzimy dwie nowe.

Czytelność w tym przykładzie nie jest na najwyższym poziomie - bardzo rzadko zajdzie potrzeba stosowania wszystkich możliwości jednocześnie. Skupmy się jednak na tym, jakie nowości się tutaj pojawiły:

  1. Podczas destrukturyzacji tablicy people zastosowałem , (przecinek) w celu pominięcia pierwszego elementu w tablicy, czyli obiektu z właściwością name: "Alicja". Gdybyś chciał pominąć więcej niż jeden element, to możesz zastosować kilka przecinków z rzędu. Zapis wyglądałby następująco: [,,, ...rest] = someArr (pomijamy 3 pierwsze elementy). W przypadku destrukturyzowania obiektu, ta składnie nie ma zastosowania, ponieważ tam po prostu wskazujemy konkretne klucze, które chcemy wyciągnąć.

  2. Drugą nowością jest destrukturyzacja zagnieżdżonego obiektu address. Zamiast wyciągać cały obiekt, wchodzimy nieco głębiej i destrukturyzujemy obiekt umieszczony wewnątrz innego obiektu. Nie ma ograniczeń co do głębokości destrukturyzacji, ale zalecam zachować umiar. Zbyt głęboka destrukturyzacja moża być trudna do odczytania.

Ostatni temat, który pozostał do omówienia, to dynamiczna destrukturyzacja. Najłatwiej będzie to zrozumieć na przykładzie:

Składnia jest tu trochę inna niż poprzednio. Żeby użyć wyrażenia jako klucz musimy zastosować nawiasy kwadratowe [ ], wewnątrz umieszczamy parametr key, czyli nazwę klucza, która będzie przekazana podczas wywołania funkcji. Ostatni krok to nadanie nowej nazwy za pomocą [key] : newName. Zdestrukturyzowana wartość znajduje się pod zmienną o nazwie newName (w przykładzie powyżej jest to property).

Podsumowanie

Temat destrukturyzacji w JavaScript został wyczerpany niemal w 100%. Nie musisz uczyć się na pamięć wszystkich możliwości, ale na pewno warto wiedzieć o ich istnieniu. Jeżeli w którymś momencie będziesz potrzebował odświeżyć wiedzę, to zachęcam do ponownego przeczytania tego artykułu lub zajrzenia do dokumentacji w MDN.

Pamiętaj również o zachowaniu zdrowego rozsądku - jeżeli obiekt posiada wiele zagnieżdżonych właściwości, które są użyte tylko raz (np. w funkcji), to prawdopodobnie nie ma sensu ich wszystkich wyciągać, a próba pójścia tą drogą może obniżyć czytelność kodu.

Jednak w większości przypadków destrukturyzacja znacznie zwiększa przejrzystość kodu, dlatego zachęcam do jej używania i eksperymentowania. Z całą pewnością doświadczenie jest tutaj bardzo ważnym czynnikiem, który znacznie ułatwia wyznaczanie granic, a jedynym sposobem na zdobycie go, jest stosowanie tej (i innych) techniki w praktyce.

Avatar: Wojciech Rygorowicz

Software Engineer / Fullstack developer

Wojciech Rygorowicz

wojciech.rygorowicz@gmail.com

Podziel się na

Dodaj komentarz

Komentarze (0)

Brak komentarzy