内存堆栈在javascript中是如何工作的

内存堆栈在javascript中是如何工作的,javascript,memory,stack,Javascript,Memory,Stack,当我们有如下代码时: 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=newa()完成后,a()中的“x”值不应该“消失”吗?包含x的堆栈也应该消失,对吗?或者,javasc

当我们有如下代码时:

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=newa()完成后,a()中的“x”值不应该“消失”吗?包含x的堆栈也应该消失,对吗?或者,javascript是否总是保留所有创建的堆栈,以防将来引用它们?但那不是很好,是不是…?

你看到的是。在另一个函数中定义的函数可以访问所有变量,甚至在外部函数返回后,也可以访问它所在的范围内的变量,但基本上,函数中的变量(和参数)都作为与该函数调用相关的对象(称为“变量对象”)的属性存在。由于绑定到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);
    });
}
乍一看,我们发现click处理程序只使用了
x
。所以它只引用了
x
,对吗


错误,引用的是变量对象,它包含
x
bigarray
。因此,
bigarray
的内容也会保留,即使函数不使用它们。这不是一个问题(而且经常很有用),但它强调了潜在的机制。(如果您确实不需要单击处理程序中的
bigarray
,您可能希望在从
foo
返回之前执行
bigarray=undefined;
,以便释放内容。)

您要查找的单词是“closure”

在另一个函数中创建
函数
,会给内部函数一个(隐藏)引用,以引用外部函数运行的本地范围

只要您保留一份
测试
的副本,该副本显式引用了
add
函数,并且该函数隐式引用了调用
a
构造函数时创建的作用域。该范围明确引用了
x
,以及函数中定义的任何其他局部变量。(包括
值和构造函数的
参数
 — 虽然您无法从内部访问它们,但添加,因为该函数自己的此/
参数
正在跟踪它们。)


当您放开
test
时,JavaScript解释器可以放开
x
,因为无法获得对该变量的引用。

在这里和您的文章链接中都有很好的解释。我认为在JavaScript中创建对象时,了解这些信息非常重要。谢谢。a()的“变量对象”与a()的作用域相同吗?变量对象只是作用域的另一个名称吗?@user227353:谢谢,很高兴能帮上忙。不,变量对象和范围略有不同
a()
的变量对象位于其作用域链的顶部,因此它是解决非限定引用的第一件事。但是如果
a()
的变量对象不能解决某个问题,那么这个问题的解决方法就会指向链上的下一个对象,等等。(还有
构造,以避免^H^H^H^H^H^H^H处理。)因为javascript中的函数也被视为“变量”,这让我想知道除了变量对象之外还有什么,是否在作用域内?@user227353:我主要是指出
a()
的变量对象上的属性并不都在它的作用域内;其所有封闭作用域的变量对象的属性也在其作用域中。从使用Javascript的角度来看,这几乎就是您需要担心的所有问题。但是对于词汇环境记录、绑定对象等的所有血淋淋的细节,请查看规范的第10节:-)这个答案非常有用,我希望我可以接受不止一个答案。