闭包是否保持整个执行上下文? [英] Do closures keep the whole execution context alive?

查看:116
本文介绍了闭包是否保持整个执行上下文?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我想知道整个上下文是保存还是只有所需的部分。
在前一种情况下,我需要以不浪费内存的方式构造函数。这应该是设计目标反正,但我想知道如果JavaScript也照顾它。



这是一个简单的例子(基于单页网页应用程序,Mikowski / Powell,第56页):

  var ctx; 
var outer_function = function(){
var dummy ='不需要输出';
var output ='output';
var inner_function = function(){
return {output:output};
}
return inner_function;
};

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

存储在闭包中的 dummy 在执行
outer_function 后,即使它不可访问,也不会使用?

解决方案

我们可以看到,Chrome消除了未使用的变量(除非有一个直接的 eval 调用)。请考虑以下代码(



c $ c> hello 在Closure作用域中存活。 unused 已消失。我们可以通过转到控制台(代码仍然暂停)并确认 hello 被定义,但访问未使用产生一个ReferenceError。



这是垃圾收集的基本原理:如果一个变量完全不可访问, 。没有人指定JavaScript引擎必须释放完全不可访问的变量,但它是一个明显的性能胜利,无法区分(在语言完整性术语)从垃圾收集未使用的变量。



但是,直接调用 eval 可以访问其他不可访问的变量。如果我们修改我们的返回函数,直接调用 eval ...

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

我们看到所有的本地Closure范围变量现在保存:





顺便说一下,这是一个主要基于性能的原因为什么 eval is evil。在代码中存在对 eval 的单个直接调用会阻止整个闭包被垃圾回收。


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?

解决方案

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 becomes completely inaccessible, it should be freed. No one specified that JavaScript engines must free completely inaccessible variables, but it's an obvious performance win that is indistinguishable (in language-completeness 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.

这篇关于闭包是否保持整个执行上下文?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆