Peo*_*are 4 javascript closures
我知道闭包通过保存对已执行函数的引用来保持执行上下文的活跃性.
我想知道整个上下文是保存还是仅保存所需的部分.
在前一种情况下,我需要以不浪费内存的方式构造函数.无论如何,这应该是设计目标,但我想知道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();
Run Code Online (Sandbox Code Playgroud)
dummy对象在执行后是否存储在闭包中,
outer_function即使它不可访问也不会被使用?
我们可以看到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);
Run Code Online (Sandbox Code Playgroud)
bar返回访问内部变量的函数hello和unused.变量hello在返回的函数内部使用,但unused不是.unused在终止后完全无法访问bar.
当我们运行此代码时,Dev Tools已经打开(为了打破debugger语句),我们看到:
这是垃圾收集的基本原则:如果变量完全无法访问,则应该释放它.没有人指定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);
Run Code Online (Sandbox Code Playgroud)
我们看到现在保留了所有本地Closure-scope变量:
您可能想知道:引擎如何可靠地检测到eval呼叫的存在?难道你不能做一些像window["ev"+"al"](s)发动机无法可靠检测的方式吗?答案是这种"间接" eval调用无法访问闭包范围变量并在全局范围内执行.只有使用标识符eval作为函数调用的一部分的直接调用才能访问局部变量,并且易于检测.
如果您有兴趣了解有关直接eval调用的更多信息,请参阅我对global.eval的回答是无法访问词法范围中的变量.
顺便说一下,这是" eval为邪恶" 的主要表现原因之一.eval在代码中存在单个直接调用可防止整个闭包被垃圾收集.