了解javascript闭包和内存使用情况

时间:2011-06-01 16:26:39

标签: javascript closures

编辑:这只是一个简单的例子,可以解决我对一个更大的程序的关注。我不会将这个实际代码用于任何事情:)

如果我跑这个 -

<!DOCTYPE html>
<html>
<head>
<script>

function update(amount, win, data)
{
    win.innerText = 'Count is ' + amount;
    setTimeout(function() { update(amount + 1, win, {data: 'something'})}, 1000);
}

window.onload = function() {

  var win = document.getElementById('item');    
  update(0, win, 0);
}
</script>
</head>

<body>
<div id="item"></div>
</body>
</html>

对setTimeout的调用可能会创建一个闭包,它将参数的内容捕获到“update”函数(amount,win,data)。因此,这些变量将保留在内存中,直到调用超时并返回,以便它们在该函数调用中可用...

但是该函数为超时的下一次迭代创建了一个 new 闭包......在第二个闭包中会捕获什么?它只是那些变量的 new 副本,还是构成函数调用一部分的那些将在新闭包中再次再次

由于每个闭包中的数据越来越大,或者这样安全合理,这最终是否会耗尽内存?

2 个答案:

答案 0 :(得分:7)

在我的理解中,当创建一个闭包时,当前的词汇上下文与它捆绑在一起。在您的情况下,它将是amount, win, data

当超时触发时,将使用此上下文来执行闭包,从而再次调用函数update;虽然它可能看起来如此,但这个调用不是递归的,因为update的先前执行已经结束,并且其原始上下文(动态,与词法不同)已经被释放。 (我认为这一点很重要,因为看起来你担心由于递归导致的堆栈增长)。

因此,再次,update再次执行,并再次设置超时并创建闭包。此闭包与当前的词法执行上下文(其中仅包含amount, win, data)捆绑在一起,并使用计时器进行调度。然后update完成并从堆栈中删除。然后再次启动计时器并再次调用更新...

所以,你不应该担心上下文的无限增长,原因有二:首先,只有词汇上下文与闭包捆绑在一起;这个电话实际上不是递归的。

答案 1 :(得分:4)

每次调用超时回调时都会创建一个新的闭包,正如您所说的那样。但是一旦执行了回调,就不再有任何引用前一个闭包的东西了,所以它可以被垃圾收集。