我们的代码如下:
function a(){
var x =0;
this.add=function(){
alert(x++);
}
}
var test = new a();
test.add(); // alert 0
test.add(); // alert 1
test.add(); // alert 2
这是如何工作的? 如果test = new a()完成,那么()中'x'的值是否应该'消失'?包含x的堆栈也应该也消失了吧?或者,javascript是否始终保留所有堆栈,以防将来引用它们?但这不会很好,是吗......?
答案 0 :(得分:6)
你要找的词是“封闭”。
在另一个函数内创建function
,为内部函数提供对外部函数运行的本地作用域的(隐藏)引用。
只要您保留test
的副本,其中明确引用add
函数,该函数具有对创建范围的隐式引用调用a
构造函数时。 该范围具有对x
的明确引用,以及函数中定义的任何其他局部变量。 (包括this
值和构造函数arguments
- 虽然您无法从add
内部访问它们,因为该函数自己的this
/ arguments
正在影响它们。)
当你放开test
时,JavaScript解释器可以放弃x
,因为无法获得对该变量的引用。
答案 1 :(得分:4)
您所看到的是closure的效果。在另一个函数中定义的函数可以访问所有变量,也可以在范围内访问 - 即使在外部函数返回之后。 More here,但基本上,函数中的变量(和参数)都作为与该函数调用相关的对象(称为“变量对象”)的属性存在。因为您绑定到this.add
的函数是在该上下文中定义的,所以它具有对该对象的持久引用,防止该对象被垃圾收集,这意味着该函数可以继续访问这些属性(例如, ,函数的变量和参数。)
您通常会听到有人说该函数会关闭x
变量,但它比这更复杂(也很有趣)。这是对变量对象的访问权限。这有影响。例如:
function foo() {
var bigarray;
var x;
bigarray = /* create a massive array consuming memory */;
document.getElementById('foo').addEventListener('click', function() {
++x;
alert(x);
});
}
乍一看,我们发现点击处理程序只使用x
。所以它只引用x
,对吧?
错误,引用的是变量对象,其中包含x
和 bigarray
。所以bigarray
的内容也会保留,即使该函数不使用它们。这不是一个问题(它经常有用),但它强调了潜在的机制。 (如果您真的不需要点击处理程序中的bigarray
内容,您可能希望在从bigarray = undefined;
返回之前执行foo
,以便释放内容。)