宿主函数返回后,在事件中可用的JavaScript局部范围变量。为什么?

时间:2019-05-23 16:30:08

标签: javascript variables scope garbage-collection

所以...我来自c ++背景,我对JS不太了解。例如:

function a()
{
   var x = 0; // Local variable

   $(document).on('mousedown', function(){console.log('down: ', x++);});
   $(document).on('mouseup', function(){console.log('up: ', x++);});
   setInterval(function(){console.log('interval: ', x++);}, 1000);

   //W3schools: 'Local variables are deleted when the function is completed.'
}
a();

为什么控制台输出看起来像这样? (在随机点击时)


interval:  0
down:  1
up:  2
interval:  3
down:  4
up:  5
interval:  6
down:  7
interval:  8
up:  9
interval:  10
down:  11
interval:  12
up:  13
interval:  14
down:  15
up:  16
interval:  17
interval:  18

我希望它是'undefined's或NaNs或null,因为x应该在范围的末尾删除,但是似乎所有这三个回调引用永远都很好...为什么?从旧的JS版本开始,这是一种新的行为还是这样?我找不到答案。

2 个答案:

答案 0 :(得分:1)

W3schools的评论不完整。大多数情况下,函数完成时确实会清除变量(不一定是立即清除,而是在下次运行垃圾回收时清除)。但这只是因为大多数时候不再有对这些变量的引用。

但是,由于javascript支持将函数用作一流对象,因此它也支持闭包。当您有这样的一行时:

x

...您正在创建一个闭包。该闭包是新函数,加上定义它的词法环境。它引用了a,因此即使x完成解析后,x也不会被垃圾回收。稍后在调用该函数时,它仍然可以很好地访问闭包变量。

Invalid operation: Result size exceeds LISTAGG limit** 仍可能被垃圾回收,但前提是所有引用它的闭包也必须被垃圾回收。在这种情况下,您可以通过取消注册mouseup和mousedown事件并取消间隔来实现。

答案 1 :(得分:0)

函数可以访问x,因为您在变量可以访问的范围内为它们提供了变量。它的计数是因为在javascript中,您没有给出实际值,而只是给出了对它的引用,因此您的所有回调仍在a()函数中引用x。并且因为它仍被引用,所以javascript的垃圾收集器不会删除它,因为它认为它仍在“使用中”(因为您的回调函数会在每次调用时使用它来增加它)。