这不是递归
它可能看起来像递归,但 setTimeout 不会创建递归。
setTimeout 的工作方式是立即返回。所以调用k
立即结束,堆栈被释放。
当超时实际发生并且go
再次发生调用时,它不是来自上一次调用的点,k
而是来自全局范围*。
* 注意:我没有使用 ECMAScript 规范中定义的范围的严格含义。我的意思是调用k
将就像您将其写在一个普通的<script></script>
标签中一样:也就是说,在任何其他函数调用之外。
关于您对关闭的担忧
k
在您的特定情况下,该函数创建的闭包中实际上包含的内容很少。唯一重要的闭包是对参数cb
和的引用myId
。即便如此,它也只会持续大约一秒钟:
#1 function k(myId, cb) {
#2 setTimeout(function(){
#3 console.log(myId); // there is a closure here to myId
#4 cb(); // and another one for cb
#5
/* But at this point in the function, setTimeout ends
* and as the function returns, there are no remaining
* references to either "cb" or "myId" accessible
* anywhere else. Which means that the GC can immediately
* free them (though in reality the GC may run a bit later)
*/
#6 }, 1000); // So one second is roughly the longest the closure lasts
}
可以更简单
我应该注意到您的代码相当复杂。如果你像这样简单地编写它,它可以写得更简单,并且根本不使用闭包(减去全局变量 i):
// Simpler, does exactly the same thing:
var i = 0;
function go () {
console.log(i);
i++;
setTimeout(go, 1000); // callback
}
go();