最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Do closures keep the whole execution context alive? - Stack Overflow

programmeradmin3浏览0评论

I understand that closures keep the execution context alive by saving a reference to the executed function.

I'm wondering whether the whole context is saved or only the required parts.
In the former case I need to structure the functions in a way that no memory is wasted. This should be the design goal anyway, but I would like to know if JavaScript takes care of it, too.

Here's a simple example (on the basis of Single Page Web Applications, Mikowski/Powell, p. 56):

var ctx;
var outer_function = function () {
    var dummy = 'not required for output';
    var output = 'output';
    var inner_function = function () {
        return { output: output };
    }
    return inner_function;
};

ctx = outer_function();
// returns { output: 'output' }
ctx();

Is the dummy object stored in the closure after the execution of outer_function even though it is not accessible and won't be used?

I understand that closures keep the execution context alive by saving a reference to the executed function.

I'm wondering whether the whole context is saved or only the required parts.
In the former case I need to structure the functions in a way that no memory is wasted. This should be the design goal anyway, but I would like to know if JavaScript takes care of it, too.

Here's a simple example (on the basis of Single Page Web Applications, Mikowski/Powell, p. 56):

var ctx;
var outer_function = function () {
    var dummy = 'not required for output';
    var output = 'output';
    var inner_function = function () {
        return { output: output };
    }
    return inner_function;
};

ctx = outer_function();
// returns { output: 'output' }
ctx();

Is the dummy object stored in the closure after the execution of outer_function even though it is not accessible and won't be used?

Share Improve this question asked Jan 11, 2016 at 13:26 PeoplewarePeopleware 1,4191 gold badge28 silver badges43 bronze badges 5
  • 2 Probably similar stackoverflow./a/864549/575527 – Joseph Commented Jan 11, 2016 at 13:30
  • I guess dummy is not stored. I might be wrong but to satisfy a closure, that variable must be referenced in a function. This reference marks it to be kept alive. – Rajesh Commented Jan 11, 2016 at 13:39
  • As fas as i know, the whole (engine-internal) Object is stored, that holds all the variables from a particular scope is "stored". But this might be differentiate between the particular JS-Engines. – Thomas Commented Jan 11, 2016 at 13:55
  • @Rajesh I had the same guess, that's why I'm asking. The answer linked by Joseph suggests the opposite. But that was a couple of years ago, maybe something's changed. – Peopleware Commented Jan 11, 2016 at 13:57
  • Related to stackoverflow./questions/35000424 – Peopleware Commented Feb 5, 2016 at 10:42
Add a ment  | 

1 Answer 1

Reset to default 9

We can see that Chrome eliminates unused variables (unless there is a direct eval call). Consider the following code (here's a fiddle to follow along with):

var bar = function() {
    var hello = "world";
    var unused = "nope";
    return function(s) { console.log(hello); debugger; return s; };
}
var g = bar();
g(1);

bar returns a function that has access to the inner variables hello and unused. The variable hello is used inside of the returned function, but unused is not. unused is entirely inaccessible after the termination of bar.

When we run this code with Dev Tools already open (to break on the debugger statement), we see:

We see that only hello has survived in the Closure scope. unused has disappeared. We can confirm this by going to the console (while the code is still paused) and seeing that hello is defined but accessing unused produces a ReferenceError.

This is the fundamental principle of garbage collection in action: if a variable bees pletely inaccessible, it should be freed. No one specified that JavaScript engines must free pletely inaccessible variables, but it's an obvious performance win that is indistinguishable (in language-pleteness terms) from not garbage collecting unused variables.

However, direct calls to eval can access otherwise inaccessible variables. If we modify our returned function to include a direct call to eval...

var foo = function() {
    var hello = "world";
    var unused = "nope";
    return function(s) { console.log(hello); debugger; return eval(s) };
}
var f = foo();
f(1);

We see that all local Closure-scope variables are now preserved:

This is because the environment cannot safely garbage collect any local variables, e.g., for fear that eval(s) might evaluate to unused.

You might wonder: how can the engine reliably detect the existence of eval calls? Couldn't you do something like window["ev"+"al"](s) instead, in a way that the engine can't reliable detect? The answer is that such an "indirect" eval call does not have access to closure-scope variables and executes in the global scope. Only direct calls that use the identifier eval as part of a function call can access local variables, and that's easy to detect.

If you're interested in learning more about direct eval calls, see my answer on global.eval is not able to visit variables in the lexical scope.

Incidentally, this is one of the main performance-based reasons why "eval is evil". The presence of a single direct call to eval in your code prevents the entire closure from being garbage-collected.

发布评论

评论列表(0)

  1. 暂无评论