Skip to content
Skip to content
Menu
Info Cafe
Info Cafe

Prosty przewodnik, który pomoże Ci zrozumieć domknięcia w JavaScript

By admin on 20 stycznia, 2021

Zamknięcia w JavaScript są jednym z tych pojęć, które wielu z trudem mieści w głowie. W poniższym artykule wyjaśnię w jasny sposób, czym jest zamknięcie, i wyjaśnię to na prostych przykładach.

Zamknięcie jest cechą w JavaScript, gdzie funkcja wewnętrzna ma dostęp do zmiennych funkcji zewnętrznej (zamykającej) – łańcuch zakresu.

Zamknięcie ma trzy łańcuchy zakresów:

  • ma dostęp do własnego zakresu – zmiennych zdefiniowanych pomiędzy nawiasami klamrowymi
  • ma dostęp do zmiennych funkcji zewnętrznej
  • ma dostęp do zmiennych globalnych

Dla niewtajemniczonych, ta definicja może wydawać się po prostu mnóstwem żargonu!

Ale czym tak naprawdę jest zamknięcie?

Przyjrzyjrzyjmy się prostemu przykładowi zamknięcia w JavaScript:

function outer() { var b = 10;
function inner() {
var a = 20;
console.log(a+b);
}
return inner;
}

Mamy tutaj dwie funkcje:

  • funkcję zewnętrzną outer, która posiada zmienną b, i zwraca funkcję inner function
  • an internal function inner, która posiada zmienną a, i uzyskuje dostęp do zmiennej outerb, w ramach swojego ciała funkcji

Zakres zmiennej b jest ograniczony do funkcji outer, a zakres zmiennej a jest ograniczony do funkcji inner.

Wywołajmy teraz funkcję outer(), a wynik działania funkcji outer() zapiszmy w zmiennej X. Następnie wywołajmy funkcję outer() po raz drugi i zapiszmy ją w zmiennej Y.

Zobaczmy krok po kroku, co się stanie, gdy funkcja outer() zostanie wywołana po raz pierwszy:

  1. Zmienna b zostaje utworzona, jej zakres zostaje ograniczony do funkcji outer(), a jej wartość zostaje ustawiona na 10.
  2. Kolejna linia to deklaracja funkcji, więc nic do wykonania.
  3. W ostatniej linii, return inner szuka zmiennej o nazwie inner, stwierdza, że ta zmienna inner jest w rzeczywistości funkcją, a więc zwraca całe ciało funkcji inner.
  4. Zawartość zwracana przez instrukcję return jest przechowywana w X.
    Tak więc, X będzie przechowywał następujące dane:
    function inner() {
    var a=20;
    console.log(a+b);
    }
  5. Funkcja outer() kończy wykonywanie, a wszystkie zmienne w zakresie outer() teraz już nie istnieją.

Ta ostatnia część jest ważna do zrozumienia. Gdy funkcja zakończy swoje wykonywanie, wszelkie zmienne, które zostały zdefiniowane wewnątrz zakresu funkcji przestają istnieć.

Czas życia zmiennej zdefiniowanej wewnątrz funkcji jest czasem życia wykonania funkcji.

Co to oznacza, że w console.log(a+b), zmienna b istnieje tylko podczas wykonywania funkcji outer(). Gdy funkcja outer zakończy wykonywanie, zmienna b już nie istnieje.

Gdy funkcja jest wykonywana po raz drugi, zmienne funkcji są tworzone ponownie i żyją tylko do momentu zakończenia wykonywania funkcji.

Tak więc, gdy outer() jest wywoływany po raz drugi:

  1. Tworzona jest nowa zmienna b, jej zakres jest ograniczony do funkcji outer(), a jej wartość jest ustawiana na 10.
  2. Kolejna linia to deklaracja funkcji, więc nic do wykonania.
  3. return inner zwraca całe ciało funkcji inner.
  4. Zawartość zwracana przez instrukcję return jest przechowywana w Y.
  5. Funkcja outer() kończy wykonywanie, a wszystkie zmienne w zakresie outer() teraz już nie istnieją.

Ważnym punktem jest to, że kiedy funkcja outer() jest wywoływana po raz drugi, zmienna b jest tworzona na nowo. Ponadto, gdy funkcja outer() zakończy wykonywanie po raz drugi, ta nowa zmienna b ponownie przestaje istnieć.

To najważniejszy punkt, z którego należy zdać sobie sprawę. Zmienne wewnątrz funkcji powstają tylko wtedy, gdy funkcja jest uruchomiona, a przestają istnieć, gdy funkcja zakończy wykonywanie.

Powróćmy teraz do naszego przykładu kodu i spójrzmy na X i Y. Ponieważ funkcja outer() w momencie wykonania zwraca funkcję, zmienne X i Y są funkcjami.

Można to łatwo sprawdzić, dodając do kodu JavaScript następujące elementy:

console.log(typeof(X)); //X is of type function
console.log(typeof(Y)); //Y is of type function

Ponieważ zmienne X i Y są funkcjami, możemy je wykonać. W języku JavaScript funkcję można wykonać, dodając () po nazwie funkcji, np. X() i Y().

Kiedy wykonujemy X() i Y(), zasadniczo wykonujemy funkcję inner .

Prześledźmy krok po kroku, co się dzieje, gdy X() jest wykonywany po raz pierwszy:

  1. Zmienna a jest tworzona, a jej wartość jest ustawiana na 20.
  2. JavaScript próbuje teraz wykonać a + b. Tutaj sprawy stają się interesujące. JavaScript wie, że a istnieje, ponieważ właśnie go utworzył. Jednak zmienna b już nie istnieje. Ponieważ b jest częścią funkcji zewnętrznej, b istniałby tylko podczas wykonywania funkcji outer(). Ponieważ funkcja outer() zakończyła wykonywanie na długo przed tym, jak wywołaliśmy X(), wszelkie zmienne znajdujące się w zakresie funkcji outer przestają istnieć, a zatem zmienna b już nie istnieje.

Jak JavaScript sobie z tym radzi?

Zamknięcia

Funkcja inner może uzyskać dostęp do zmiennych funkcji zamykającej dzięki zamknięciom w JavaScript. Innymi słowy, funkcja inner zachowuje łańcuch zakresu funkcji zamykającej w czasie, gdy funkcja zamykająca została wykonana, a zatem może uzyskać dostęp do zmiennych funkcji zamykającej.

W naszym przykładzie, funkcja inner zachowała wartość b=10, gdy funkcja outer() została wykonana, i nadal ją zachowuje (zamyka).

Teraz odwołuje się do swojego łańcucha zakresu i zauważa, że ma wartość zmiennej b w swoim łańcuchu zakresu, ponieważ zamknął wartość b w ramach zamknięcia w punkcie, w którym funkcja outer została wykonana.

Tak więc, JavaScript zna a=20 i b=10, i może obliczyć a+b.

Możesz to zweryfikować, dodając następującą linię kodu do powyższego przykładu:

Otwórz element Inspect w Google Chrome i przejdź do Konsoli. Możesz rozwinąć element, aby faktycznie zobaczyć element Closure (pokazany w przedostatniej linii poniżej). Zauważ, że wartość b=10 jest zachowana w elemencie Closure nawet po tym, jak funkcja outer() zakończy swoje działanie.

Zmienna b=10 jest zachowana w Closure, Closures in Javascript

Powróćmy teraz do definicji domknięć, którą widzieliśmy na początku i zobaczmy, czy teraz ma ona więcej sensu.

Więc funkcja wewnętrzna ma trzy łańcuchy zakresu:

  • dostęp do własnego zakresu – zmienna a
  • dostęp do zmiennych funkcji outer – zmienna b, którą zawiera
  • dostęp do dowolnych zmiennych globalnych, które mogą być zdefiniowane

Zamknięcia w akcji

Aby podkreślić znaczenie domknięć, rozszerzmy przykład o trzy linie kodu:

Kiedy uruchomisz ten kod, zobaczysz następujące wyjście w console.log:

a=20 b=10
a=20 b=11
a=20 b=12
a=20 b=10

Przeanalizujmy ten kod krok po kroku, aby zobaczyć co dokładnie się dzieje i zobaczyć domknięcia w akcji!

var X = outer(); // outer() invoked the first time

Funkcja outer() jest wywoływana po raz pierwszy. Wykonywane są następujące kroki:

  1. Tworzona jest zmienna b i ustawiana na 10
    Tworzona jest zmienna c, i ustawiona na 100
    Nazwijmy to b(first_time) i c(first_time) dla naszego własnego odniesienia.
  2. Funkcja inner jest zwracana i przypisywana do X
    W tym momencie, zmienna b jest dołączona do łańcucha zakresu funkcji inner jako domknięcie z b=10, ponieważ inner używa zmiennej b.
  3. Funkcja outer kończy wykonywanie, a wszystkie jej zmienne przestają istnieć. Zmienna c już nie istnieje, chociaż zmienna b istnieje jako zamknięcie wewnątrz inner.
var Y= outer(); // outer() invoked the second time
  1. Zmienna b jest tworzona od nowa i jest ustawiana na 10
    Zmienna c jest tworzona od nowa.
    Zauważ, że mimo iż outer() została wykonana raz, zanim zmienne b i c przestały istnieć, po zakończeniu wykonywania funkcji są one tworzone jako zupełnie nowe zmienne.
    Nazwijmy je b(second_time) i c(second_time) dla naszego własnego odniesienia.
  2. Funkcja inner zostaje zwrócona i przypisana do Y
    W tym momencie zmienna b jest dołączona do łańcucha zakresu funkcji inner jako zamknięcie z b(second_time)=10, ponieważ inner używa zmiennej b.
  3. Funkcja outer kończy wykonywanie, a wszystkie jej zmienne przestają istnieć.
    Zmienna c(second_time) już nie istnieje, choć zmienna b(second_time) istnieje jako domknięcie wewnątrz inner.

Zobaczmy teraz, co się stanie, gdy poniższe linie kodu zostaną wykonane:

X(); // X() invoked the first time
X(); // X() invoked the second time
X(); // X() invoked the third timeY(); // Y() invoked the first time

Gdy X() jest wywoływany po raz pierwszy,

  1. tworzona jest zmienna a, i ustawiona na 20
  2. wartość a=20, wartość b pochodzi z wartości zamknięcia. b(first_time), więc b=10
  3. zmienne a i b zwiększają się o 1
  4. X() kończy wykonywanie i wszystkie jego zmienne wewnętrzne – zmienna a – przestają istnieć.
    Jednakże b(first_time) został zachowany jako domknięcie, więc b(first_time) nadal istnieje.

Gdy X() jest wywoływany po raz drugi,

  1. zmienna a jest tworzona od nowa, i ustawiona na 20
    Każda poprzednia wartość zmiennej a już nie istnieje, ponieważ przestała istnieć, gdy X() zakończył wykonywanie za pierwszym razem.
  2. wartość a=20
    wartość b pobierana jest z wartości zamknięcia – b(first_time)
    Zauważ również, że zwiększyliśmy wartość b o 1 z poprzedniego wykonania, więc b=11
  3. zmienne a i b są zwiększane o 1 ponownie
  4. X() kończy wykonywanie i wszystkie jego zmienne wewnętrzne – zmienna a – przestają istnieć
    Jednakże, b(first_time) jest zachowany, ponieważ zamknięcie nadal istnieje.

Gdy X() jest wywoływany po raz trzeci,

  1. zmienna a jest tworzona od nowa, i ustawiona na 20
    Wcześniejsza wartość zmiennej a już nie istnieje, ponieważ przestała istnieć, gdy X() zakończył wykonywanie za pierwszym razem.
  2. wartość a=20, wartość b pochodzi z wartości zamknięcia – b(first_time)
    Zauważ również, że w poprzednim wykonaniu zwiększyliśmy wartość b o 1, więc b=12
  3. zmienne a i b są inkrementowane przez 1 ponownie
  4. X() kończy wykonywanie, a wszystkie jego zmienne wewnętrzne – zmienna a – przestają istnieć
    Jednakże b(first_time) jest zachowana, gdyż domknięcie nadal istnieje

Gdy Y() jest wywoływane po raz pierwszy,

  1. zmienna a jest tworzona od nowa i ustawiana na 20
  2. wartość a=20, wartość b pochodzi z wartości zamknięcia – b(second_time), więc b=10
  3. zmienne a i b są inkrementowane o 1
  4. Y() kończy wykonywanie, i wszystkie jego zmienne wewnętrzne – zmienna a – przestają istnieć
    Jednakże b(second_time) został zachowany jako domknięcie, więc b(second_time) nadal istnieje.

Uwagi końcowe

Zamknięcia są jednym z tych subtelnych pojęć w JavaScript, które są trudne do uchwycenia na początku. Ale kiedy już je zrozumiesz, zdasz sobie sprawę, że nie mogło być inaczej.

Mam nadzieję, że te wyjaśnienia krok po kroku pomogły Ci naprawdę zrozumieć koncepcję domknięć w JavaScript!

Inne artykuły:

  • Szybki przewodnik po funkcjach „samowywołujących się” w JavaScript
  • Zrozumienie zakresu funkcji vs. zakresu bloku w JavaScript
  • Jak używać obietnic w JavaScript
  • Jak zbudować prostą animację Sprite w JavaScript

Zobacz wpisy

Aric Almirola, Smithfield przedłużają kontrakt ze Stewart-Haas Racing
Co to jest blackface?

Dodaj komentarz Anuluj pisanie odpowiedzi

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

Najnowsze wpisy

  • Firebush (Polski)
  • Prognoza stawek CD na 2021 rok: Stopy procentowe prawdopodobnie pozostaną na niskim poziomie, ale mogą wzrosnąć w dalszej części roku
  • Jak ustrukturyzować dokumentację systemu zarządzania jakością
  • Zdrowe Gry i Zajęcia dla Dzieci | UIC Online Informatics
  • Wheat Ales (American) (Polski)
  • Korzyści z karmienia piersią po roku
  • Czy bezpiecznie jest wrzucać fusy z kawy do zlewu | Atomic Plumbing
  • Cool-Down After Your Workout (Polski)
  • Nasza praca
  • Najlepsza ręczna maszyna do szycia do kupienia: 2020

Meta

  • Zaloguj się
  • Kanał wpisów
  • Kanał komentarzy
  • WordPress.org

Archiwa

  • Marzec 2021
  • Luty 2021
  • Styczeń 2021
  • Grudzień 2020
  • DeutschDeutsch
  • NederlandsNederlands
  • EspañolEspañol
  • FrançaisFrançais
  • PortuguêsPortuguês
  • ItalianoItaliano
  • PolskiPolski
  • 日本語日本語
©2021 Info Cafe | WordPress Theme by SuperbThemes.com