setInterval() **调用的函数如何在封闭函数 returns 之后访问封闭函数的变量?

How does the function **called by** setInterval() access the variables of the enclosing function, after the enclosing function returns?

我对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");
};

每 50 毫秒调用一次的 Enclozee 从内部访问变量 xintrvl,但是这些操作在 Encloser 返回后很久才发生(通过在控制台上记录 returning now)。这怎么可能? Encloser 是否让垃圾收集器等待?这种行为不安全吗?以及如何在 Encloser 函数 returns 之后将基本类型 x 从函数堆栈中移除?

这个概念被称为“闭包”。虽然有些语言会在调用堆栈完成时擦除所有局部变量,但 javascript 不是其中之一。只要存在从内存根到该变量的路由,变量就不会被垃圾回收。

因此,只要某些东西仍然引用该内部函数,就不会收集内部函数使用的任何变量。在这种情况下,是 setInterval 的内部代码保留了对内部函数的引用,并且它将继续这样做,直到您调用 clearInterval。在那之后,不再有对该函数的引用,因此它可以与它引用的变量一起被垃圾回收。

很安全

这是因为在创建 Enclozee 时,它还会创建一个 闭包 ,允许它访问在其创建时范围内的所有变量创建,即使在其原始上下文结束后

您可以在此处阅读更多相关信息 - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures