当前位置:  开发笔记 > 编程语言 > 正文

闭包是否使整个执行环境保持活力?

如何解决《闭包是否使整个执行环境保持活力?》经验,为你挑选了1个好方法。

我知道闭包通过保存对已执行函数的引用来保持执行上下文的活跃性.

我想知道整个上下文是保存还是仅保存所需的部分.
在前一种情况下,我需要以不浪费内存的方式构造函数.无论如何,这应该是设计目标,但我想知道JavaScript是否也会处理它.

这是一个简单的例子(基于单页Web应用程序,Mikowski/Powell,第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();

dummy对象在执行后是否存储在闭包中, outer_function即使它不可访问也不会被使用?



1> apsillers..:

我们可以看到Chrome删除了未使用的变量(除非有直接eval调用).考虑以下代码(这里是一个小提琴):

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

bar返回访问内部变量的函数hellounused.变量hello在返回的函数内部使用,但unused不是.unused在终止后完全无法访问bar.

当我们运行此代码时,Dev Tools已经打开(为了打破debugger语句),我们看到:

Dev Tools显示hello在Closure范围内幸存下来.unused已经消失了.我们可以通过转到控制台来确认这一点(当代码仍然暂停时)并且看到它hello已定义但是访问unused会产生ReferenceError.

这是垃圾收集的基本原则:如果变量完全无法访问,则应该释放它.没有人指定JavaScript引擎必须释放完全无法访问的变量,但这是一个明显的性能胜利,与无垃圾收集未使用的变量无法区分(在语言完整性条款中).

但是,直接调用eval 可以访问其他无法访问的变量.如果我们修改我们返回的函数以包含直接调用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);

我们看到现在保留了所有本地Closure-scope变量:

eval(s)可能会评估unused.

您可能想知道:引擎如何可靠地检测到eval呼叫的存在?难道你不能做一些像window["ev"+"al"](s)发动机无法可靠检测的方式吗?答案是这种"间接" eval调用无法访问闭包范围变量并在全局范围内执行.只有使用标识符eval作为函数调用的一部分的直接调用才能访问局部变量,并且易于检测.

如果您有兴趣了解有关直接eval调用的更多信息,请参阅我对global.eval的回答是无法访问词法范围中的变量.

顺便说一下,这是" eval为邪恶" 的主要表现原因之一.eval在代码中存在单个直接调用可防止整个闭包被垃圾收集.

推荐阅读
coco2冰冰
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有