我对Javascript的理解是,一旦一个函数完成了它的工作,该函数的局部变量就会被丢弃。但是,请考虑以下代码:
document.onkeydown = function Encloser(evt){
evt = evt || window.event;
switch(evt.keyCode){
case 88:
var x = 50;
var intrvl = setInterval(function Enclozee(){
console.log(x);
ctx.clearRect(0, 0, cnv.width, cnv.height);
actionRoutine(x--);
if(x < 0)
clearInterval(intrvl);
}, 50);
break;
}
// Redraw Routine
console.log(evt.keyCode);
ctx.clearRect(0, 0, cnv.width, cnv.height);
actionRoutine(50);
console.log("returning now");
};
每50ms调用一次的Enclozee
从其内部访问变量x
和intrvl
,但这些操作发生在Encloser
返回很久之后(通过在控制台上记录returning now
(。这怎么可能?Encloser
是否使垃圾收集器等待?这种行为不安全吗?在Encloser
函数返回后,如何不从函数堆栈中删除基元类型x
?
这是安全的
这是因为创建Enclozee
时,它还会创建一个闭包,允许它访问创建时范围内的所有变量,即使在它们的原始上下文结束之后也是如此
你可以在这里阅读更多信息-https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
这个概念被称为"闭合";。虽然有些语言在调用堆栈完成时会擦除所有本地变量,但javascript不是其中之一。只要存在从内存根到变量的路由,变量就不会被垃圾回收。
因此,只要某个东西仍然引用该内部函数,内部函数使用的任何变量都不会被收集。在这种情况下,是setInterval的内部代码保持对内部函数的引用,并且它将继续这样做,直到您调用clearInterval。在那之后,就不再有对函数的引用了,所以它可以和它引用的变量一起被垃圾收集。