(Side note: For anyone wondering whether Ben's code is syntactically correct: Yes, it is, as of ES2015; it wouldn't be in ES5 or earlier. It's using the new "method definition" syntax ES2015 defines for object initializers.)
Re your first question, on this code:
var o = {
foo() {
setTimeout(function() {}, 10000);
}
};
o.foo();
o = null;
The object initially assigned to o
is eligible for GC right away, even before the timer callback, because nothing keeps a reference to it after the o = null;
statement.
But there are other objects that may or may not be eligible for GC, it depends on theory (the specification) vs. practice (implementation optimizations not ruled out by the spec):
Until the timer callback occurs, the timer mechanism keeps a reference to the anonymous function, and so that anonymous function isn't eligible for GC.
In theory, the anonymous function has a reference to the environment object in which it was created, which in turn has a reference to foo
, and so the anonymous function keeps both the environment and foo
in memory until the timer fires, releases its reference, and the anonymous function is eligible for GC.
In practice, since the anonymous function doesn't reference foo
or any arguments or local variables within foo
(and doesn't use eval
), a JavaScript implementation is free to optimize and allow foo
and that environment object to be GC'd even though the setTimeout
call still has a reference to that anonymous function. (And some do indeed do closure optimization, such as V8.) They can do that because we can't see any side-effects from it other than memory consumption or the lack thereof.
Re your additional question, on this code:
var o = {
bar: 0,
foo() {
setTimeout(function() { o.bar; }, 10000);
}
};
o.foo();
o = null;
The object itself is still eligible for GC immediately.
Re foo
and the environment object for the call to it:
In theory, they're both retained (as they were above). In practice, I don't know if that affects the optimization that the engine can do around foo
and the environment for the call or not. It shouldn't, because the o
variable is bound to the global environment, not the one set up by the call to foo
, and so the environment chain could be edited to skip the environment created by the call to foo
. So engines could optimize it, and at a total guess I'd say they probably do, but I don't know that they do.