Wyrażenie lambda w języku C # ma również zamknięcia, ale rzadko jest omawiane przez społeczności lub książki w języku C #. Widzę o wiele więcej osób zajmujących się JavaScript i książek mówi o jego zamknięciach niż w świecie C #. Dlaczego?
Wyrażenie lambda w języku C # ma również zamknięcia, ale rzadko jest omawiane przez społeczności lub książki w języku C #. Widzę o wiele więcej osób zajmujących się JavaScript i książek mówi o jego zamknięciach niż w świecie C #. Dlaczego?
Odpowiedzi:
Ponieważ javascript nie ma takiej funkcji, jak przestrzenie nazw, i można dość łatwo zepsuć wszystkie obiekty globalne.
Dlatego ważne jest, aby móc izolować część kodu we własnym środowisku wykonawczym. Zamknięcie jest do tego idealne.
Takie użycie zamknięcia nie ma sensu w języku takim jak C #, w którym masz przestrzenie nazw, klasy itd. Do izolowania kodu i nie umieszczania wszystkiego w zasięgu globalnym.
Bardzo powszechną praktyką dla kodu javascript jest pisanie go w następujący sposób:
(function(){
// Some code
})();
Jak widać, jest to deklaracja funkcji anonimowej, po której następuje natychmiastowe wykonanie. Zatem do wszystkiego zdefiniowanego w funkcji nie można uzyskać dostępu z zewnątrz, a Ty nie zepsujesz globalnego zasięgu. Kontekst wykonania tej funkcji pozostanie aktywny, dopóki użyje go jakiś kod, np. Funkcje zagnieżdżone zdefiniowane w tym kontekście, które można przekazać jako wywołanie zwrotne lub cokolwiek innego.
JavaScript jest językiem zupełnie innym niż C #. Nie jest zorientowany obiektowo, jest zorientowany prototypowo. To prowadzi do bardzo różnych praktyk na końcu.
W każdym razie zamknięcia są dobre, więc używaj ich, nawet w C #!
EDYCJA: Po krótkiej dyskusji na czacie stackoverflow, myślę, że należy odpowiedzieć na tę odpowiedź.
Funkcja w przykładowym kodzie nie jest zamknięciem. Jednak ta funkcja może definiować zmienne lokalne i funkcje zagnieżdżone. Wszystkie zagnieżdżone funkcje korzystające z tych zmiennych lokalnych są zamknięciami.
Jest to przydatne do udostępniania niektórych danych w zestawie funkcji bez naruszania globalnego zasięgu. Jest to najczęstsze użycie zamknięcia w javascript.
Zamykanie jest znacznie potężniejsze niż udostępnianie takich danych, ale bądźmy realistami, większość programistów nie wie nic o programowaniu funkcjonalnym. W języku C # użyłbyś klasy lub przestrzeni nazw do tego rodzaju zastosowań, ale JS nie zapewnia tej funkcji.
Z zamknięciem możesz zrobić znacznie więcej niż tylko chronić globalny zasięg, ale to właśnie zobaczysz w kodzie źródłowym JS.
Prawdopodobnie dlatego, że popularne implementacje orientacji obiektowej JavaScript zależą od zamknięć. Spójrzmy na prosty przykład:
function counter() {
var value = 0;
this.getValue = function() { return value; }
this.increase = function() { value++; }
}
var myCounter = new counter();
console.log(myCounter.getValue());
myCounter.increase();
console.log(myCounter.getValue());
Metody getValue
i increase
faktycznie są zamknięciami, zamykającymi zmienną value
.
Ponieważ wiele bibliotek, dzięki którym JavaScript jest „znośny”, korzysta z nich.
Spójrz na JQuery , Prototype lub MooTools , żeby wymienić tylko trzy popularne. Każda z tych bibliotek udostępnia each
metodę dla swoich kolekcji jako preferowany sposób iteracji, który wykorzystuje funkcję iteracji. Ta funkcja, podczas uzyskiwania dostępu do wartości w zakresie zewnętrznym, będzie zamknięciem:
[1,2,3].each(function(item) {
console.log(item);
});
I na tym się nie kończy: wywołania zwrotne w Ajaxie, obsługa zdarzeń w Ext.js itp. Wszystkie przyjmują funkcje, a jeśli nie chcesz nadpisywać kodu setkami funkcji, które są wywoływane dokładnie raz, zamykanie jest właściwym rozwiązaniem.
console.log
jest zdefiniowany w zewnętrznym zakresie, podobnie console
jak „dowolna zmienna”. I dlaczego w efekcie powstaje pętla for, która nie robi nic innego, zła praktyka?
Zgadzam się z innymi odpowiedziami, że „dobre” kodowanie w JavaScript jest bardziej zależne od zamknięć. Jednak oprócz tego prawdopodobnie chodzi tylko o to, jak długo ta funkcja działa w każdym języku. JavaScript ma w zasadzie zamknięcia od najwcześniejszych wdrożeń. Z drugiej strony C # ma je tylko od wersji 3.0, która została wydana wraz z Visual Studio 2008.
Wielu programistów C #, z którymi się spotkałem, nadal pracuje nad projektami 2.0. I nawet jeśli pracują w wersji 3.0 lub 4.0, często nadal używają idiomów 2.0. Uwielbiam zamknięcia; miejmy nadzieję, że będą one częściej używane w języku C #, gdy koncepcja rozprzestrzenia się wśród programistów C #.
Głównym powodem jest to, że C # jest typowo statyczny, a funkcje mają dostęp tylko do jednego, z góry określonego środowiska, co utrudnia użyteczność zamknięć.
Z drugiej strony, w JavaScript, zamknięcia pozwalają funkcjom zachowywać się jak metody, gdy są dostępne jako właściwość obiektu, a będąc obiektami pierwszej klasy, można je również wstrzykiwać do różnych środowisk, które umożliwiają działanie podprogramów w różnych kontekstach.
Jednym z powodów, dla których musiałem się o nich dowiedzieć, było to, że kiedy przeglądasz elementy DOM (lub cokolwiek innego naprawdę), chcesz mieć możliwość „zamknięcia” lub „enkapsulacji” zakresu zmiennej. Jak w przykładzie zamieszczonym tutaj: /programming/5606059/how-to-create-closure-in-loop-and-store-it-in-variable-for-later-execution