所以...我来自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版本开始,这是一种新的行为还是这样?我找不到答案。
答案 0 :(得分:1)
W3schools的评论不完整。大多数情况下,函数完成时确实会清除变量(不一定是立即清除,而是在下次运行垃圾回收时清除)。但这只是因为大多数时候不再有对这些变量的引用。
但是,由于javascript支持将函数用作一流对象,因此它也支持闭包。当您有这样的一行时:
x
...您正在创建一个闭包。该闭包是新函数,加上定义它的词法环境。它引用了a
,因此即使x
完成解析后,x
也不会被垃圾回收。稍后在调用该函数时,它仍然可以很好地访问闭包变量。
Invalid operation: Result size exceeds LISTAGG limit**
仍可能被垃圾回收,但前提是所有引用它的闭包也必须被垃圾回收。在这种情况下,您可以通过取消注册mouseup和mousedown事件并取消间隔来实现。
答案 1 :(得分:0)
函数可以访问x,因为您在变量可以访问的范围内为它们提供了变量。它的计数是因为在javascript中,您没有给出实际值,而只是给出了对它的引用,因此您的所有回调仍在a()函数中引用x。并且因为它仍被引用,所以javascript的垃圾收集器不会删除它,因为它认为它仍在“使用中”(因为您的回调函数会在每次调用时使用它来增加它)。