2012-11-22 11 views
7

Zakładając miałem tę funkcję, która (z jakiegoś dziwnego powodu) zwraca jego arguments obiekt do rozmówcy:Czy obiekt Arguments wycieknie?

function example(a, b/* ...*/) { 
    var c = // some processing 
    return arguments; 
} 

Czy przechowywania wynik inwokacji (var d=example();) zapobiegania zmienną środowiska example (zawierający a, b, c itd.) Ze śmieci? Wewnętrzne ustawiacze i moduły pobierające z Arguments object mogą nadal się do niego odwoływać, podobnie jak funkcja zwrócona z zamknięcia.

Wiem, że praktycznie nie ma przypadków użycia (i omijanie przedmiotów Argumenty jest uważane za złą praktykę, najprawdopodobniej z powodu ich podobieństwa do tablic), ale jest to bardziej teoretyczne pytanie. W jaki sposób obsługują to różne implementacje EcmaScript?

+0

Dziwną rzeczą w 'argumentach' jest to, że nazwane parametry są faktycznie ** aliasami ** dla elementów pseudo-tablicy. Spróbuj! Jeśli zmienisz 'argumenty [0]', zmieni się również 'a'! Nie sądzę, że z tego powodu przecieka. – Pointy

+1

Naprawdę? Myślałem, że jest odwrotnie: 'arguments [0]' jest aliasem dla 'a' :-) Algorytm opisany w specyfikacji wskazuje, że indeksy' argumentów' były ustawiaczami i pobierającymi z "ParameterMap" i link do rekordu środowiska inwokacji - możliwy powód do wycieku imho. Dlatego też pytam o rzeczywiste implementacje ... – Bergi

+0

Cóż, myślę, że jest to rodzaj tajemnicy, która jest aliasem, dla którego :-) Myślę, że ponieważ obiekt argumentów jest w zasadzie ** jest ** zestaw parametrów, nie potrzebuje odniesienia do zamknięcia ani niczego, więc inne niż pamięć, której używa bezpośrednio nie "przypina" niczego innego. To tylko przeczucie i nie znam prawdziwej historii. – Pointy

Odpowiedz

3

Rozważ to:

var x = function() { 
    return arguments; 
} 
console.log(x() === x()); 

To fałszywe, bo to nie jest to samo arguments przedmiot: to (dla każdego invokation z x) w nowo wybudowanym obiekcie, który ma wartości wszystkich params przechowywanych wewnątrz. Jednak ma ona właściwości arguments:

var y = x([]); 
console.log(y instanceof Object); // true 
console.log(y instanceof Array); // false 
console.log(y.length); // 1 
console.log(y.callee + '');  // function() { return arguments; } 

jeszcze coś więcej do tego. Oczywiście, przedmioty wysyłane do funkcji jako jej params nie będą zbierane przez GC jeśli arguments zwrócone są:

var z = x({some: 'value'}); 
console.log(z[0]); // {some:'value'} 

To normalne: mimo wszystko, można uzyskać podobny wynik, oświadczając jakiś lokalny obiekt wewnątrz funkcji, przypisywanie wartość pierwszego parametru funkcji jako własności obiektu "0", a następnie zwrócenie tego obiektu. W obu przypadkach obiekt, o którym mowa, będzie nadal "w użyciu", więc nie ma sprawy, jak sądzę.

Ale co z tym?

var globalArgs; 
var returnArguments = function() { 
    var localArgs = arguments; 
    console.log('Local arguments: '); 
    console.log(localArgs.callee.arguments); 
    if (globalArgs) { // not the first run 
    console.log('Global arguments inside function: '); 
    console.log(globalArgs.callee.arguments); 
    } 
    return arguments; 
} 
globalArgs = returnArguments('foo'); 
console.log('Global arguments outside function #1: '); 
console.log(globalArgs.callee.arguments); 
globalArgs = returnArguments('bar'); 
console.log('Global arguments outside function #2: '); 
console.log(globalArgs.callee.arguments); 

wyjściowa:

Local arguments: ["foo"] 
Global arguments outside function #1: null 
Local arguments: ["bar"] 
Global arguments inside function: ["bar"] 
Global arguments outside function #2: null 

Jak widać, jeśli wrócisz arguments obiekt i przypisać go do jakiejś zmiennej wewnątrz funkcji jego callee.argument punktów własności do tego samego zestawu danych, jak sama arguments; to znów jest oczekiwane. Ale poza funkcją variable.callee.arguments jest równa null (nie niezdefiniowana).

+0

'variable.callee.arguments' nie jest tym samym, co' arguments', jest to niestandardowa konstrukcja. Zobacz moją odpowiedź na [to pytanie] (http://stackoverflow.com/q/11939736/825789). – bfavaretto

0

Bez przeprowadzania jakichkolwiek badań konkretnego silnika JavaScript trudno jest jednoznacznie odpowiedzieć. Twierdzę jednak, że relacja między argumentsObject a kontekstem utworzonym przez example jest taka sama, jak każdej innej zmiennej lokalnej i jej kontekście hosta.

Oznacza to, że zapisanie wartości nie wymaga również zapisania kontekstu.

Jedno zastrzeżenie stanowi własność arguments.callee który jest odniesienie do związku (tj Function), który dana argumentsObject jest związany.Ta właściwość nie istnieje jednak w trybie ścisłym, a także has been deprecated.

Poza tym uważam, że można bezpiecznie założyć, że powrót i przechowywanie argumentsObject nie doprowadzi do wycieku pamięci.

+0

'argument.callee' po prostu odwołuje się do funkcji' przyklad', czyż nie? Pytałem tylko o inne wartości w kontekście wykonywania 'przykladu', np.' C'. – Bergi

+0

Tak to właśnie robi. Nie jestem do końca pewien, o co ci chodzi. Zmienna lokalna (jak 'c') nie będzie odwoływała się w' arguments' 'Object'. – FK82

+0

Jasne, ale to jest pytanie. Odczytywanie [specyfikacji dotyczącej obiektu 'arguments'] (http://es5.github.com/#x10.6), wewnętrzne obiekty pobierające/ustawiające obiektu argumentu odwołują się do rekordu środowiska zmiennych (w tym' c'). – Bergi