Od czasu do czasu widzę wzmiankę o „zamknięciach” i próbowałem to sprawdzić, ale Wiki nie zawiera wyjaśnienia, które rozumiem. Czy ktoś mógłby pomóż mi tutaj?
Komentarze
- Jeśli znasz Javę / C #, mam nadzieję, że ten link pomoże- http://www.developerfusion.com/article/8251/the-beauty-of-closures/
- Zamknięcia są trudne do zrozumienia. Spróbuj kliknąć wszystkie linki w pierwszym zdaniu tego artykułu w Wikipedii i zrozumieć je artykuły najpierw.
- stackoverflow.com/questions/36636/what-is-a-closure
- Co ' to jednak podstawowa różnica między zamknięciem a klasą? OK, klasa z tylko jedną metodą publiczną.
- @biziclop: Możesz emulują zamknięcie klasą (to ' jest tym, co mają do zrobienia programiści Java). Ale ' są zwykle nieco mniej rozwlekłe do tworzenia i nie Nie musisz ręcznie zarządzać tym, co ' niepotrzebnym. (Zapaleni lispersi zadają podobne pytanie, ale prawdopodobnie dochodzą do innego wniosku – że obsługa obiektów obiektowych na poziomie języka jest niepotrzebna, gdy masz zamknięcia).
Odpowiedź
(Zastrzeżenie: to jest podstawowe wyjaśnienie; jeśli chodzi o definicję, trochę upraszczam)
Najprostszym sposobem myślenia o zamknięciu jest funkcja , którą można zapisać jako zmienną (nazywaną „pierwszą -class function „), która ma specjalną możliwość dostępu do innych zmiennych lokalnych w zakresie, w jakim została utworzona.
Przykład (JavaScript):
var setKeyPress = function(callback) { document.onkeypress = callback; }; var initialize = function() { var black = false; document.onclick = function() { black = !black; document.body.style.backgroundColor = black ? "#000000" : "transparent"; } var displayValOfBlack = function() { alert(black); } setKeyPress(displayValOfBlack); }; initialize();
Funkcje 1 przypisane do document.onclick
i displayValOfBlack
to domknięcia. Widać, że oba odnoszą się do zmiennej boolowskiej black
, ale ta zmienna jest przypisana poza funkcją. Ponieważ black
jest lokalna dla zakresu, w którym funkcja została zdefiniowana , wskaźnik do tej zmiennej jest zachowany.
Jeśli umieścisz to na stronie HTML:
- Kliknij, aby zmienić na czarny
- Naciśnij [enter], aby zobaczyć „prawda”
- Kliknij ponownie, zmienia kolor z powrotem na biały
- Naciśnij [enter], aby zobaczyć „false”
To pokazuje, że obaj mają dostęp do tego samego black
, i może być użyty do przechowywania stanu bez żadnego obiektu opakowania.
Wywołanie setKeyPress
ma na celu zademonstrowanie, jak można przekazać funkcję tak jak każda zmienna. zakres zachowany w zamknięciu jest nadal tym, w którym funkcja została zdefiniowana.
Zamknięcia są często używane jako programy obsługi zdarzeń, zwłaszcza w JavaScript i ActionScript. Dobre użycie domknięć pomoże ci niejawnie powiązać zmienne z programami obsługi zdarzeń bez konieczności tworzenia opakowania obiektu. Jednak nieostrożne użycie doprowadzi do wycieków pamięci (na przykład, gdy nieużywany, ale zachowany program obsługi zdarzeń jest jedyną rzeczą, która może zatrzymać duże obiekty w pamięci, zwłaszcza obiekty DOM, zapobiegając czyszczeniu pamięci).
1: Właściwie wszystkie funkcje w JavaScript są domknięciami.
Komentarze
- Czytając twoją odpowiedź, poczułem, jak w mojej głowie zapala się żarówka. Bardzo cenione! 🙂
- Ponieważ
black
jest zadeklarowane wewnątrz funkcji, nie ' nie zostałoby zniszczone, gdy stos się rozwija. ..? - @gablin, czyli to, co jest unikalne w językach, które mają zamknięcia. Wszystkie języki z funkcją czyszczenia pamięci działają w podobny sposób – gdy nie ma już żadnych odwołań do obiektu, można go zniszczyć. Za każdym razem, gdy funkcja jest tworzona w JS, lokalny zasięg jest powiązany z tą funkcją, dopóki ta funkcja nie zostanie zniszczona.
- @gablin, to ' to dobre pytanie. Nie ' nie sądzę, aby mogli ' t & mdash; ale wspomniałem tylko o zbieraniu śmieci, ponieważ to, czego używa JS, i to ' jest tym, do czego zdawałeś się odnosić, mówiąc ” Ponieważ
black
jest zadeklarowany wewnątrz funkcji, nie ' t zostałby zniszczony „. Pamiętaj również, że jeśli zadeklarujesz obiekt w funkcji, a następnie przypiszesz go do zmiennej, która żyje gdzieś indziej, obiekt ten zostanie zachowany, ponieważ istnieją do niego inne odniesienia. - Objective-C (i C poniżej clang) obsługuje bloki, które są zasadniczo domknięciami, bez czyszczenia pamięci. Wymaga obsługi w czasie wykonywania i ręcznej interwencji w zakresie zarządzania pamięcią.
Odpowiedź
Zamknięcie to po prostu inny sposób patrzenia na obiekt. Obiekt to dane, do których jest przypisana co najmniej jedna funkcja. Zamknięcie to funkcja, z którą jest powiązana co najmniej jedna zmienna. Te dwa są zasadniczo identyczne, przynajmniej na poziomie implementacji. Prawdziwa różnica polega na tym, skąd się biorą.
W programowaniu obiektowym deklaruje się klasę obiektową, definiując z góry jej zmienne składowe i metody (funkcje składowe), a następnie tworzy się instancje ta klasa. Każde wystąpienie zawiera kopię danych składowych zainicjowaną przez konstruktora. Następnie masz zmienną typu obiektowego i przekazujesz ją jako fragment danych, ponieważ uwaga skupia się na jej naturze jako danych.
Z drugiej strony w zamknięciu obiekt nie jest zdefiniowane z góry, takie jak klasa obiektów, lub utworzone przez wywołanie konstruktora w kodzie. Zamiast tego piszesz zamknięcie jako funkcję wewnątrz innej funkcji. Zamknięcie może odnosić się do dowolnej zmiennej lokalnej funkcji zewnętrznej, a kompilator wykrywa to i przenosi te zmienne z obszaru stosu funkcji zewnętrznej do deklaracji obiektu ukrytego zamknięcia. Otrzymujesz wtedy zmienną typu zamknięcia i nawet jeśli jest to w zasadzie obiekt pod maską, przekazujesz go jako odniesienie do funkcji, ponieważ skupiamy się na jego naturze jako funkcji.
Komentarze
- +1: dobra odpowiedź. Możesz zobaczyć zamknięcie jako obiekt z tylko jedną metodą, a dowolny obiekt jako zbiór domknięć na niektórych typowych danych bazowych (zmienne składowe obiektu '). Myślę, że te dwa poglądy są dość symetryczne.
- Bardzo dobra odpowiedź. W rzeczywistości wyjaśnia znaczenie zamknięcia.
- @Mason Wheeler: Gdzie są przechowywane dane dotyczące zamknięcia? W stosie jak funkcja? Czy w stercie jak obiekt?
- @RoboAlex: W stercie, ponieważ ' jest obiektem, który wygląda jak funkcja .
- @RoboAlex: Miejsce przechowywania zamknięcia i przechwyconych danych zależy od implementacji. W C ++ może być przechowywany na stercie lub na stosie.
Odpowiedź
Termin zamknięcie wynika z faktu, że fragment kodu (blok, funkcja) może mieć wolne zmienne, które są zamknięte (tj. związane z wartością) przez środowisko, w którym zdefiniowano blok kodu.
Weźmy na przykład definicję funkcji Scala :
def addConstant(v: Int): Int = v + k
W treści funkcji znajdują się dwie nazwy (zmienne) v
i k
wskazując dwie wartości całkowite. Nazwa v
jest związana, ponieważ jest zadeklarowana jako argument funkcji addConstant
(patrząc na deklarację funkcji wiemy, że v
otrzyma wartość po wywołaniu funkcji). Nazwa k
jest wolna dla funkcji addConstant
, ponieważ funkcja nie zawiera wskazówki co do wartości k
jest powiązane z (i jak).
Aby ocenić wywołanie takie jak:
val n = addConstant(10)
musimy przypisać k
wartość, która może wystąpić tylko wtedy, gdy nazwa k
jest zdefiniowana w kontekście, w którym addConstant
jest zdefiniowane. Na przykład:
def increaseAll(values: List[Int]): List[Int] = { val k = 2 def addConstant(v: Int): Int = v + k values.map(addConstant) }
Teraz, gdy zdefiniowaliśmy addConstant
w kontekście, w którym k
jest zdefiniowane, addConstant
stało się zamknięciem , ponieważ wszystkie jego wolne zmienne są teraz zamknięte (powiązane z wartością): addConstant
może być wywoływana i przekazywana tak, jakby była funkcją. Zwróć uwagę, że wolna zmienna k
jest powiązana z wartością, gdy zamknięcie jest zdefiniowane , podczas gdy zmienna argumentu v
jest powiązana, gdy zamknięcie jest wywołane .
Więc zamknięcie jest w zasadzie funkcją lub blokiem kodu, który może uzyskać dostęp do wartości nielokalnych poprzez swoje wolne zmienne po tym, jak zostaną one związane z kontekstem.
W wielu językach, jeśli użyj zamknięcia tylko wtedy, gdy możesz je uczynić anonimowym , np.
def increaseAll(values: List[Int]): List[Int] = { val k = 2 values.map(v => v + k) }
Zauważ, że funkcja bez wolnych zmiennych jest specjalnym przypadkiem zamknięcia (z pustym zestawem wolnych zmiennych). Analogicznie, funkcja anonimowa jest szczególnym przypadkiem anonimowego zamknięcia , tj. funkcja anonimowa to anonimowe zamknięcie bez wolnych zmiennych.
Komentarze
- To dobrze pasuje do zamkniętych i otwartych formuł w logice. Dziękuję za odpowiedź.
- @RainDoctor: Wolne zmienne są definiowane w formułach logicznych i wyrażeniach rachunku lambda w podobny sposób: lambda w wyrażeniu lambda działa jak kwantyfikator we wzorach logicznych ze zmiennymi swobodnymi / związanymi .
Odpowiedź
Proste wyjaśnienie w JavaScript:
var closure_example = function() { var closure = 0; // after first iteration the value will not be erased from the memory // because it is bound with the returned alertValue function. return { alertValue : function() { closure++; alert(closure); } }; }; closure_example();
alert(closure)
użyje wcześniej utworzonej wartości closure
. Zwrócona przestrzeń nazw funkcji alertValue
zostanie połączona z przestrzenią nazw, w której znajduje się zmienna closure
. Gdy usuniesz całą funkcję, wartość zmiennej closure
zostanie usunięta, ale do tego czasu funkcja alertValue
będzie zawsze mogła odczytać / zapisać wartość zmiennej closure
.
Jeśli uruchomisz ten kod, pierwsza iteracja przypisze wartość 0 do zmiennej closure
i przepisz funkcję na:
var closure_example = function(){ alertValue : function(){ closure++; alert(closure); } }
A ponieważ alertValue
potrzebuje zmiennej lokalnej closure
aby wykonać funkcję, wiąże się z wartością wcześniej przypisanej zmiennej lokalnej closure
.
A teraz za każdym razem, gdy wywołujesz closure_example
, zapisze zwiększoną wartość zmiennej closure
, ponieważ alert(closure)
jest związane.
closure_example.alertValue()//alerts value 1 closure_example.alertValue()//alerts value 2 closure_example.alertValue()//alerts value 3 //etc.
Komentarze
- dziękuję, nie ' t przetestuj kod =) wszystko wydaje się teraz w porządku.
Odpowiedź
„Zamknięcie” to w istocie, jakiś stan lokalny i jakiś kod, połączone w pakiet. Zazwyczaj stan lokalny pochodzi z otaczającego (leksykalnego) zakresu, a kod jest (zasadniczo) funkcją wewnętrzną, która jest następnie zwracana na zewnątrz. Zamknięcie jest wtedy połączeniem przechwyconych zmiennych, które widzi funkcja wewnętrzna, i kodu funkcji wewnętrznej.
Jest to jedna z tych rzeczy, która jest niestety nieco trudna do wyjaśnienia, ponieważ nieznajomym.
Jedna analogia, której z powodzeniem użyłem w przeszłości, brzmiała: „wyobraź sobie, że mamy coś, co nazywamy„ książką ”, w zamkniętym pokoju,„ książka ”to ta kopia tam, w rogu , TAOCP, ale na zamknięciu stołu jest to ta kopia książki z Akt Drezdeńskich. Więc w zależności od tego, w jakim zamknięciu jesteś, kod „daj mi książkę” skutkuje różnymi rzeczami.
Komentarze
- Zapomniałeś tego: en.wikipedia.org/wiki/Closure_(computer_programming) w Twojej odpowiedzi.
- Nie, świadomie zdecydowałem się nie zamykać tej strony.
- ” Stan i funkcja. „: Czy funkcję C ze zmienną lokalną
static
można uznać za zamknięcie? Czy domknięcia w Haskell obejmują stan? - @Giorgio Zamknięcia w Haskell czy (jak sądzę) zamykają argumenty w zakresie leksykalnym, w których ' zostały ponownie zdefiniowane w, więc ja ' d powiedz ” tak ” (chociaż w najlepszym razie nie znam Haskella). Funkcja AC ze zmienną statyczną jest w najlepszym przypadku bardzo ograniczonym zamknięciem (naprawdę chcesz mieć możliwość tworzenia wielu domknięć z jednej funkcji, ze zmienną lokalną
static
, masz dokładnie jeden). - Zadałem to pytanie celowo, ponieważ uważam, że funkcja C ze zmienną statyczną nie jest zamknięciem: zmienna statyczna jest zdefiniowana lokalnie i znana tylko wewnątrz zamknięcia, nie ma do niej dostępu środowisko. Nie jestem też w 100% pewien, ale sformułowałbym twoje stwierdzenie w drugą stronę: używasz mechanizmu zamykania do tworzenia różnych funkcji (funkcja to definicja zamknięcia + powiązanie dla swoich wolnych zmiennych).
Odpowiedź
Trudno jest zdefiniować, czym jest zamknięcie bez zdefiniowania pojęcia „stanu”.
Zasadniczo , w języku z pełnym zakresem leksykalnym, który traktuje funkcje jako wartości pierwszej klasy, dzieje się coś wyjątkowego. Gdybym miał zrobić coś takiego:
function foo(x) return x end x = foo
Zmienna x
nie tylko odwołuje się do function foo()
, ale odwołuje się również do stanu foo
, który pozostawiono w momencie ostatniego zwrócenia. Prawdziwa magia ma miejsce, gdy foo
ma inne funkcje dokładniej zdefiniowane w swoim zakresie; przypomina swoje własne mini-środowisko (tak jak „normalnie” definiujemy funkcje w środowisku globalnym).
Funkcjonalnie może rozwiązać wiele takich samych problemów, jak C ++ (C?) słowo kluczowe „s„ static ”, które zachowuje stan zmiennej lokalnej podczas wielu wywołań funkcji; jednak bardziej przypomina to zastosowanie tej samej zasady (zmiennej statycznej) do funkcji, ponieważ funkcje są wartościami pierwszej klasy; zamknięcie dodaje obsługę zapisywanego stanu całej funkcji (nie ma to nic wspólnego z funkcjami statycznymi C ++).
Traktowanie funkcji jako wartości pierwszej klasy i dodanie obsługi domknięć oznacza również, że możesz mieć więcej niż jedną instancję tej samej funkcji w pamięci (podobnie jak w klasach). Oznacza to, że możesz ponownie użyć ten sam kod bez konieczności resetowania stanu funkcji, jak jest to wymagane, gdy mamy do czynienia ze zmiennymi statycznymi C ++ wewnątrz funkcji (może się to mylić?).
Oto kilka testów obsługi zamykania Lua .
--Closure testing --By Trae Barlow -- function myclosure() print(pvalue)--nil local pvalue = pvalue or 10 return function() pvalue = pvalue + 10 --20, 31, 42, 53(53 never printed) print(pvalue) pvalue = pvalue + 1 --21, 32, 43(pvalue state saved through multiple calls) return pvalue end end x = myclosure() --x now references anonymous function inside myclosure() x()--nil, 20 x() --21, 31 x() --32, 42 --43, 53 -- if we iterated x() again
wyniki:
nil 20 31 42
Może to być trudne i prawdopodobnie jest różne z języka na język, ale w Lua wydaje się, że za każdym razem, gdy funkcja jest wykonywana, jej stan jest resetowany. Mówię to, ponieważ wyniki z powyższego kodu byłyby inne, gdybyśmy mieli dostęp do funkcja / stan bezpośrednio (zamiast zwracanej funkcji anonimowej), ponieważ pvalue
zostanie zresetowana z powrotem do 10; ale jeśli uzyskamy dostęp do stanu myclosure przez x (funkcja anonimowa), zobaczysz, że pvalue
żyje i ma się gdzieś w pamięci. Podejrzewam, że jest w tym coś więcej, ktoś może lepiej wyjaśnić naturę implementacji.
PS: Nie znam ani odrobiny C ++ 11 (poza tym, co jest w poprzednich wersjach), więc zwróć uwagę, że to nie jest porównanie między zamknięciami w C ++ 11 i Lua. Ponadto wszystkie „linie narysowane” z Lua do C ++ są podobieństwami, ponieważ zmienne statyczne i zamknięcia nie są w 100% takie same; nawet jeśli są czasami używane do rozwiązywania podobnych problemów.
W powyższym przykładzie kodu nie jestem pewien, czy funkcja anonimowa, czy funkcja wyższego rzędu jest uważana za zamknięcie?
Odpowiedź
Zamknięcie to funkcja, która ma skojarzony stan:
W perlu tworzysz takie zamknięcia:
#!/usr/bin/perl # This function creates a closure. sub getHelloPrint { # Bind state for the function we are returning. my ($first) = @_;a # The function returned will have access to the variable $first return sub { my ($second) = @_; print "$first $second\n"; }; } my $hw = getHelloPrint("Hello"); my $gw = getHelloPrint("Goodby"); &$hw("World"); // Print Hello World &$gw("World"); // PRint Goodby World
Jeśli spojrzymy na nową funkcjonalność dostarczoną w C ++.
Pozwala ona również na powiązanie aktualnego stanu z obiektem:
#include <string> #include <iostream> #include <functional> std::function<void(std::string const&)> getLambda(std::string const& first) { // Here we bind `first` to the function // The second parameter will be passed when we call the function return [first](std::string const& second) -> void { std::cout << first << " " << second << "\n"; }; } int main(int argc, char* argv[]) { auto hw = getLambda("Hello"); auto gw = getLambda("GoodBye"); hw("World"); gw("World"); }
Odpowiedź
Rozważmy prostą funkcję:
function f1(x) { // ... something }
Ta funkcja jest nazywana funkcją najwyższego poziomu, ponieważ nie jest zagnieżdżona w żadnej innej funkcji. Co Funkcja JavaScript wiąże ze sobą listę obiektów o nazwie „ Łańcuch zakresu ”. Ten łańcuch zasięgu jest uporządkowana lista obiektów E. Każdy z tych obiektów definiuje pewne zmienne.
W funkcjach najwyższego poziomu łańcuch zasięgu składa się z pojedynczego obiektu, obiektu globalnego. Na przykład funkcja f1
powyżej ma łańcuch zasięgu zawierający pojedynczy obiekt, który definiuje wszystkie zmienne globalne. (zwróć uwagę, że termin „obiekt” nie oznacza tutaj obiektu JavaScript, jest to po prostu obiekt zdefiniowany w implementacji, który działa jako kontener zmiennych, w którym JavaScript może „wyszukiwać” zmienne).
Gdy to wywoływana jest funkcja, JavaScript tworzy coś, co nazywa się „Obiekt aktywacji” i umieszcza go na górze łańcucha zasięgu. To obiekt zawiera wszystkie zmienne lokalne (na przykład x
tutaj). W związku z tym mamy teraz dwa obiekty w łańcuchu zasięgu: pierwszy to obiekt aktywacji, a pod nim obiekt globalny.
Zwróć uwagę bardzo uważnie, że te dwa obiekty są umieszczane w łańcuchu zasięgu w RÓŻNYCH momentach. Obiekt globalny jest umieszczany, gdy funkcja jest zdefiniowana (tj. kiedy JavaScript przeanalizował funkcję i utworzył obiekt funkcji), a obiekt aktywacji wchodzi, gdy funkcja jest wywoływana.
Więc teraz wiemy to:
- Każda funkcja ma powiązany z nią łańcuch zasięgu
- Kiedyfunkcja jest zdefiniowana (podczas tworzenia obiektu funkcji), JavaScript zapisuje łańcuch zasięgu z tą funkcją
- W przypadku funkcji najwyższego poziomu łańcuch zasięgu zawiera tylko obiekt globalny w czasie definicji funkcji i dodaje dodatkowy obiekt aktywacji na górze w czasie wywołania
Sytuacja staje się interesująca, gdy mamy do czynienia z funkcjami zagnieżdżonymi. Stwórzmy więc jeden:
function f1(x) { function f2(y) { // ... something } }
Kiedy f1
zostanie zdefiniowany, otrzymamy dla niego łańcuch zasięgu zawierający tylko obiekt globalny.
Teraz, gdy f1
zostanie wywołany, łańcuch zasięgu f1
otrzymuje obiekt aktywacji. Ten obiekt aktywacji zawiera zmienną x
i zmienną f2
, która jest funkcją. Pamiętaj, że f2
jest definiowany.Dlatego w tym momencie JavaScript zapisuje również nowy łańcuch zasięgu dla f2
. Łańcuch zasięgów zapisany dla tej funkcji wewnętrznej to bieżący łańcuch zasięgu. Bieżący zakres w efekcie łańcuch f1
„s. Dlatego f2
” łańcuch zasięgu to f1
„s bieżący łańcuch zasięgu – zawierający obiekt aktywacji f1
i obiekt globalny.
Kiedy wywoływana jest f2
, otrzymuje własny obiekt aktywacji zawierający y
, dodany do łańcucha zasięgu, który już zawiera obiekt aktywacji f1
i obiekt globalny.
Jeśli w , jego łańcuch zasięgu zawierałby trzy obiekty w czasie definicji (2 obiekty aktywacji dwóch funkcji zewnętrznych i obiekt globalny) i 4 w czasie wywołania.
teraz my unders i jak działa łańcuch zasięgu, ale nie rozmawialiśmy jeszcze o domknięciach.
Kombinacja obiektu funkcji i zakresu (zestaw zmiennych wiązań) gdzie zmienne funkcji są rozwiązywane w literaturze informatycznej nazywane jest zamknięciem – JavaScript, ostateczny przewodnik Davida Flanagana
Większość funkcji jest wywoływana przy użyciu tego samego łańcucha zasięgu, który obowiązywał, gdy funkcja została zdefiniowana, i nie ma znaczenia, że chodzi o zamknięcie. Zamknięcia stają się interesujące, gdy są wywoływane w innym łańcuchu zasięgu niż ten, który obowiązywał, gdy zostały zdefiniowane. Dzieje się tak najczęściej, gdy zagnieżdżony obiekt funkcji jest zwrócony z funkcji, w której został zdefiniowany.
Kiedy funkcja zwraca, ten obiekt aktywacji jest usuwany z łańcucha zasięgu. Jeśli nie było funkcji zagnieżdżonych, nie ma więcej odwołań do obiektu aktywacji i zostaje on usunięty. Gdyby zdefiniowano funkcje zagnieżdżone, każda z tych funkcji ma odniesienie do łańcucha zasięgu, a ten łańcuch odnosi się do obiektu aktywacji.
Jeśli jednak te zagnieżdżone obiekty funkcji pozostały w swojej funkcji zewnętrznej, wtedy oni sami zostaną zebrani wraz z obiektem aktywacji, do którego się odnosili. Ale jeśli funkcja definiuje funkcję zagnieżdżoną i zwraca ją lub przechowuje gdzieś we właściwości, wówczas pojawi się odniesienie zewnętrzne do funkcji zagnieżdżonej. Nie zostanie on usunięty, a obiekt aktywacji, do którego się odnosi, również nie zostanie zebrany.
W powyższym przykładzie nie zwracamy f2
z f1
, stąd po powrocie wywołania f1
obiekt aktywacji zostanie usunięty z łańcucha zasięgu i wyrzucony jako śmieci. Ale gdybyśmy mieli coś takiego:
function f1(x) { function f2(y) { // ... something } return f2; }
W tym przypadku zwracany f2
będzie miał łańcuch zasięgu, który będzie zawiera obiekt aktywacji f1
, dlatego nie zostanie usunięty. W tym momencie, jeśli zadzwonimy do f2
, będzie on mógł uzyskać dostęp do f1
zmiennej „s x
mimo że „wypadliśmy z f1
.
W związku z tym widzimy, że funkcja zachowuje swój łańcuch zasięgu razem z nią i łańcuchem zasięgu przyjdź wszystkie obiekty aktywacji funkcji zewnętrznych. To jest istota domknięcia. Mówimy, że funkcje w JavaScript są „o zasięgu leksykalnym” , co oznacza, że zapisują zakres, który był aktywny, gdy zostały zdefiniowane, w przeciwieństwie do zakresu, który był aktywny, gdy zostały wywołane.
Istnieje wiele potężnych technik programowania, które obejmują zamknięcia, takie jak aproksymacja zmiennych prywatnych , programowanie sterowane zdarzeniami, częściowe zastosowanie itp.
Należy również pamiętać, że wszystko to dotyczy wszystkich języków, które obsługują domknięcia. Na przykład PHP (5.3+), Python, Ruby itp.
Odpowiedź
Zamknięcie to optymalizacja kompilatora (inaczej cukier syntaktyczny?). Niektórzy nazywają to także Obiektem biednego człowieka .
Zobacz odpowiedź Erica Lipperta : (fragment poniżej)
Kompilator wygeneruje następujący kod:
private class Locals { public int count; public void Anonymous() { this.count++; } } public Action Counter() { Locals locals = new Locals(); locals.count = 0; Action counter = new Action(locals.Anonymous); return counter; }
Ma to sens?
Poza tym prosiłeś o porównania. VB i JScript tworzą domknięcia w prawie taki sam sposób.
Komentarze
- Ta odpowiedź jest CW, ponieważ nie ' nie zasługuję na punkty dla Erica ' to świetna odpowiedź.Proszę, zagłosuj za tym, jak uważasz za stosowne. HTH
- -1: Twoje wyjaśnienie jest zbyt zakorzenione w C #. Zamknięcie jest używane w wielu językach i jest czymś więcej niż tylko cukrem syntaktycznym w tych językach i obejmuje zarówno funkcję, jak i stan.
- Nie, zamknięcie nie jest ani tylko ” optymalizacja kompilatora ” ani cukier syntaktyczny. -1