Articles

Jak działają domknięcia w JavaScript, prostym językiem angielskim

JavaScript jest szeroko przyjętym językiem, którego możesz użyć do zbudowania czegokolwiek, od prostej strony docelowej po aplikację klasy produkcyjnej, full-stack. Wraz z rozwojem JavaScript i programowania w ogóle, programiści zdali sobie sprawę, że paradygmat programowania zorientowanego obiektowo (OOP) jest niepożądany w większości przypadków użycia. Programowanie funkcyjne pojawiło się jako rozwiązanie wielu bolączek związanych z OOP.

Zamknięcia są szeroko dyskutowanym tematem w świecie programowania funkcyjnego, ale często są one definiowane luźno i w technicznym żargonie. Zrobimy co w naszej mocy, aby wyjaśnić jak działają zamknięcia w JavaScript w terminologii laika.

Pod koniec tego poradnika, powinieneś zrozumieć:

  • Jak zidentyfikować domknięcia
  • Czym jest domknięcie i jak zachowuje się w stosunku do kontekstu wykonania i stosu wywołań
  • Powszechne przypadki użycia domknięć

Zrozumienie domknięć w JavaScript

Zaczniemy od pokazania jak wygląda domknięcie.

Spróbuj uruchomić ten kod samodzielnie. Technicznie rzecz biorąc, funkcja o nazwie makeCounter zwraca inną funkcję o nazwie increment. Ta funkcja increment ma dostęp do zmiennej count nawet po wykonaniu funkcji makeCount. Częścią zamknięcia jest tutaj zmienna count; jest ona dostępna dla funkcji increment, gdy zostanie zdefiniowana, nawet po tym, jak makeCounter zakończy działanie. Druga część to funkcja increment.

Wyobraź sobie, że masz dom i ogród, który go otacza. Gdy otworzysz drzwi do ogrodu i zamkniesz je, nie możesz ich już otworzyć ponownie – ogród staje się niedostępny. Jesteś głodny, a na szczęście w ogrodzie rośnie drzewo pomarańczowe i jabłoń. Bierzesz mały woreczek, zrywasz pomarańczę i jabłko i wracasz do domu. Pamiętaj, że nie możesz już wrócić na zewnątrz.

Teraz, kiedy już jesteś w swoim domu, możesz wyjąć pomarańczę lub jabłko z torby i zjeść je, kiedy tylko zgłodniejesz. Mała torebka w tym przykładzie jest zamknięciem. Zamknięcie zawiera wszystkie zmienne i funkcje, które były dostępne dla ciebie, gdy byłeś w ogrodzie, nawet jeśli jesteś w domu i nie możesz wyjść na zewnątrz.

Zobaczmy, jak to wygląda w kodzie:

Ponieważ zmienna fruits jest dostępna dla zwracanej funkcji, gdy makeFruitGarden jest wykonywana, zmienna fruits i funkcja wewnętrzna stają się zamknięciem. Kiedy consumeFruit jest wykonywany, zwracany jest fruit – ostatni element z tablicy fruits, ponieważ pop() jest używany. Gdy oba owoce zostaną skonsumowane/zjedzone, nie pozostanie nic do zjedzenia.

Zrozumienie zakresu leksykalnego

Aby naprawdę zrozumieć domknięcia, powinieneś znać termin „zakres”. Zakres leksykalny to wymyślne określenie bieżącego środowiska względem tego, do czego się odnosisz.

W poniższym przykładzie zakres zmiennej o nazwie myName nazywany jest „zakresem globalnym”.

// global scopeconst myName = "John Doe"function displayName() { // local/function scope console.log(myName);};displayName()

Mogłeś zobaczyć tę koncepcję odniesioną podczas czytania o tym, jak var nie jest block-scoped i jak constlet jest. Ważne jest, aby pamiętać, że w JavaScript funkcja zawsze tworzy swój własny zakres. Nazywa się to zakresem local lub function, jak pokazano w przykładzie kodu.

Jeśli zwracałeś uwagę, możesz myśleć, że myName i displayName są częścią zamknięcia. Miałbyś rację! Ale ponieważ funkcja i zmienna tutaj istnieją w zakresie globalnym, nie ma zbyt wiele wartości w nazywaniu tego zamknięciem.

W JavaScript istnieje wiele rodzajów zakresów, ale jeśli chodzi o zamknięcia, istnieją trzy zakresy, które powinieneś znać:

  1. Zakres globalny jest domyślnym zakresem, w którym wszyscy żyją. Pomyśl o nim jak o swojej ulicy
  2. Zewnętrzny zakres funkcji jest funkcją, która zwraca funkcję. Ma ona swój własny zakres. Pomyśl o tym jak o swoim ogrodzie
  3. Wewnętrzny/lokalny zakres funkcji to zwrócona funkcja, która staje się zamknięciem. Pomyśl o tym jak o swoim domu

Teraz zagłębmy się w kilka przypadków użycia.

Wspólne przypadki użycia domknięć

Currying

Funkcja currying jest kolejną potężną koncepcją w programowaniu funkcyjnym. Aby zaimplementować funkcję curry w JavaScript, użyjesz domknięć.

Currying funkcji może być opisany jako przekształcanie funkcji i jest wykonywany w ten sposób: add(1, 2, 3) do add(1)(2)(3).

function add(a) { return function(b) { return function(c) { return a + b + c; }; };};add(1)(2)(3) // returns 6

Funkcja add przyjmuje pojedynczy argument, a następnie zwraca dwie funkcje, które są zagnieżdżone jedna za drugą. Celem currying jest wzięcie kilku argumentów i w końcu skończenie z pojedynczą wartością.

Funkcje wyższego rzędu

Celem funkcji wyższego rzędu jest wzięcie funkcji jako argumentu i zwrócenie wyniku. Metody tablicowe takie jak map i reduce są przykładami funkcji wyższego rzędu.

const arrayOfNumbers = ;const displayNumber = (num) => { console.log(num);}arrayOfNumbers.forEach(displayNumber)

Funkcja wyższego rzędu Array.prototype.forEach przyjmuje tutaj displayNumber jako argument, a następnie wykonuje go dla każdego elementu w arrayOfNumbers. Jeśli używałeś frameworka UI, takiego jak Vue lub React, możesz być zaznajomiony z komponentami wyższego rzędu, które są zasadniczo tym samym, co funkcje wyższego rzędu.

Jaka jest więc różnica między funkcjami wyższego rzędu a curryingiem? Podczas gdy funkcja wyższego rzędu przyjmuje funkcję jako argument i zwraca wartość, funkcja curried zwraca funkcję jako wynik, co ostatecznie prowadzi do wartości.

Menedżery elementów DOM

Jest to popularny wzorzec projektowy często używany do uzyskiwania i ustawiania właściwości elementów DOM. W poniższym przykładzie, stworzymy menedżera elementów do stylizacji elementów.

makeStyleManager zwraca obiekt, który daje dostęp do dwóch funkcji, które są częścią domknięcia obok zmiennych element i currentStyles. Nawet po tym, jak makeStyleManager zakończy wykonywanie, funkcje getStyle i setStyle mają dostęp do zmiennych.

Wniosek

Zamknięcia w języku JavaScript mogą być trudne do zrozumienia, nawet dla programistów z doświadczeniem zawodowym pod swoim paskiem. Zrozumienie domknięć ostatecznie uczyni cię lepszym programistą.

Powinieneś teraz być w stanie zidentyfikować domknięcie, gdy jest ono używane w bazie kodu, która wygląda dziwnie lub nie ma sensu. Zamknięcia są krytycznym pojęciem w programowaniu funkcjonalnym i mam nadzieję, że ten przewodnik pomógł Ci zrobić krok naprzód w Twojej podróży w kierunku ich opanowania.

LogRocket: Debugowanie błędów JavaScript łatwiejsze dzięki zrozumieniu kontekstu

Debugowanie kodu jest zawsze żmudnym zadaniem. Ale im lepiej rozumiesz swoje błędy, tym łatwiej jest je naprawić.

LogRocket pozwala Ci zrozumieć te błędy w nowy i unikalny sposób. Nasze rozwiązanie monitorujące frontend śledzi zaangażowanie użytkownika w Twój JavaScript frontend, aby dać Ci możliwość dowiedzenia się, co dokładnie zrobił użytkownik, co doprowadziło do błędu.

LogRocket zapisuje logi konsoli, czasy ładowania strony, ślady ścieżek, powolne żądania/odpowiedzi sieciowe z nagłówkami + ciałami, metadane przeglądarki oraz logi niestandardowe. Zrozumienie wpływu Twojego kodu JavaScript nigdy nie będzie łatwiejsze!

Wypróbuj go za darmo.

Dalsza lektura

  • „Nigdy nie rozumiałem zamknięć JavaScript” – Dogłębny, techniczny przewodnik do zrozumienia, jak działa zamknięcie. Idealny dla kogoś, kto chce zrozumieć domknięcia w odniesieniu do ExecutionContext, stosu wywołań, środowiska leksykalnego, itp.
  • MDN reference for JavaScript closures – Szybki przewodnik po domknięciach (w tym niektóre powszechne pułapki) na wypadek, gdybyś potrzebował szybko wyczyścić swoją pamięć
  • „Master the JavaScript Interview: What is a Closure?” – Domknięcia wyjaśnione przez Erica Elliota; świetne dla programistów, którzy rozumieją koncepcje programowania funkcyjnego

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *