2011-02-09 4 views
9

Po prostu z ciekawości, czy zamknięcia w JavaScript uzyskują odniesienie do całego "środowiska zewnętrznego", czy też zwracana funkcja jest analizowana, aby zobaczyć, które zmienne w zewnętrznym zasięgu się odsyła, a następnie otrzymuje tylko odniesienia do nich?Czy zamknięcia w JavaScript mają odwołanie do pełnej funkcji zewnętrznej lub czy otrzymują tylko odniesienia do zmiennych, których faktycznie używają?

+0

Przypuszczam, że jedynym sposobem na przetestowanie tego byłoby stworzenie kontekstu, który ma kilka ogromnych zmiennych, stworzenie zamknięcia, które uzyskuje dostęp do innych zmiennych w kontekście, a następnie "wystarczające" alokacje i rezygnację, które rzuca śmieci i zobacz, czy pamięć dla ogromnych zmiennych jest uwolniona, czy nie. W przeciwnym razie jest to tylko kwestia akademicka specyficzna dla tłumacza, prawda? – Phrogz

Odpowiedz

5

Teoretycznie funkcja zagnieżdżona w JavaScript ma dostęp do wszystkich zmiennych we wszystkich zawierających zakresy. Po napotkaniu identyfikatora jest on rozwiązywany względem łańcucha zasięgu , który jest listą zawierającą obiekty, których właściwościami są zmienne i parametry funkcji każdego kontekstu wykonawczego zawierającego (tj. Funkcję otaczającą), najbardziej wewnętrzną, plus obiekt globalny w koniec. Obiekt funkcyjny ciągnie za sobą łańcuch zasięgu, gdziekolwiek się znajduje.

Jednak te obiekty zmiennych i łańcuch zasięgu są tylko konstrukcjami specyfikacji i nie są dostępne bezpośrednio, więc implementacje mogą dowolnie wybierać optymalizacje, w tym analizować kod funkcji i ujawniać tylko zmienne, do których dostęp ma funkcja i dowolny funkcje zagnieżdżone w nim, o ile specyfikacja zawsze wydaje się być spełniona. Jednak najlepiej jest założyć, że jeśli masz ogromny obiekt, który jest dostępny poprzez zamknięcie funkcji, ten olbrzymi obiekt będzie się trzymał co najmniej do czasu, aż ta funkcja nie zostanie zebrana.

Jeśli chcesz uzyskać więcej informacji na ten temat, przeczytaj specyfikację ECMAScript. Dobrym punktem wyjścia będzie sekcja 10.1.4: http://bclary.com/2004/11/07/#a-10.1.4. Nie jest to aktualna wersja specyfikacji, ale stanowi punkt odniesienia dla wszystkich aktualnych głównych przeglądarek.

5

Odpowiedź brzmi "tak i nie". Gdy funkcja "wycieka" z aktywacji funkcji, cały kontekst zostaje zachowany *. Ponieważ jednak nie ma możliwości odwołania się do samego kontekstu, kod funkcji nie może "zbadać" kontekstu (ów). Tak więc:

function leaker() { 
    var i = 100, j = "hello there"; 
    return function() { 
    i = i - 1; 
    return i == 0; 
    } 
} 

Zwrócona funkcja może odnosić się tylko do "i". Zmienna "j" może się trzymać, ale nie ma możliwości, aby kod w tej zwracanej funkcji "znalazł" ją.

* Piszę, że kontekst został zachowany, co uważam za prawdziwe, ale technicznie jest to sprawa tłumacza/środowiska wykonawczego.

+2

Oznacza to, że w zasadzie otrzymuje się przecieki pamięci, jeśli zdefiniujesz jakiś duży obiekt w kontekście, ponieważ pozostanie on w pamięci przez cały czas trwania zamknięcia, nawet jeśli nie jest przez niego używany. – Sam

+0

Cóż, nie jestem pewien, jak sprytni są śmieciarze; mogą mieć sposób radzenia sobie z tym, choć wydaje mi się to dość sci-fi. Jest to interesujące pytanie i naprawdę nie jestem ekspertem od JavaScriptu :-) – Pointy

+0

@Pointy Myślę, że jest blog na temat zamknięcia powodującego wycieki pamięci, jeden używa obiektów typu instantiate, a drugi to zamknięcie. – kjy112

Powiązane problemy