Assuming I had this sloppy-mode function, which (for some odd reason) returns its arguments
object to the caller:
function example(a, b/* ...*/) {
var c = // some processing
return arguments;
}
Does storing the result of an invocation (var d=example();
) prevent the variable environment of example
(containing a
, b
, c
etc) from being garbage-collected? The internal setters and getters of the Arguments object might still refer to it, just like a function returned from a closure does. Demo:
function example(a, b) {
var c = Array(1000).fill(0); // some large object
return {
args: arguments,
set: function(x) { a = x; },
get: function() { return a; }
};
}
var d = example('init');
console.log(d.get());
d.args[0] = 'arguments update'; // assigns the `a` variable
console.log(d.get());
d.set('variable update');
console.log(d.args); // reads the `a` variable
I know there is hardly a use case (and passing around Arguments objects is considered bad practice, most likely because of their similarity to arrays), but this is more a theoretical question. How do different EcmaScript implementations handle this? Is it implemented close to the spec?
I would expect c
to be garbage-collected like with a normal closure and not to be leaked, but what about b
? What would happen if I delete
the properties of the arguments
object?
Consider this:
var x = function() {
return arguments;
}
console.log( x() === x() );
It's false, because it's not the same arguments
object: it's (for each invokation of x
) a newly constructed object that has the values of all the params stored within. Yet it has properties of 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; }
Yet there's more to this. Obviously, objects sent into function as its params will not be collected by GC if arguments
are returned:
var z = x({some: 'value'});
console.log(z[0]); // {some:'value'}
This is expected: after all, you can get the similar result by declaring some local object inside the function, assigning the value of the function's first parameter as its object '0' property, then returning this object. In both case the referred object will still be "in use", so no big deal, I suppose.
But what about this?
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);
Output:
Local arguments: ["foo"]
Global arguments outside function #1: null
Local arguments: ["bar"]
Global arguments inside function: ["bar"]
Global arguments outside function #2: null
As you see, if you return arguments
object and assign it to some variable, inside the function its callee.argument
property points to the same set of data as arguments
itself; that's, again, expected. But outside the function variable.callee.arguments
is equal to null (not undefined).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With