JavaScript 在主机函数 returns 之后的事件中可用的局部范围变量。为什么?
JavaScript local scope variable available in event after host function returns. Why?
所以...我来自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”或 NaN 或 null,因为 x 应该在范围的末尾被删除,但似乎所有三个回调都永远引用它......为什么?它是一种新行为还是自旧 JS 版本以来就这样工作?我找不到答案。
函数可以访问 x,因为您在可访问的范围内为它们提供了该变量。它计数是因为在 javascript 中你没有给出实际值而只是对它的引用,所以你所有的回调仍然引用 a() 函数内的 x 。因为它仍然被引用 javascript 的垃圾收集器不会删除它,因为它认为它仍然是 'in use',它确实是(因为你的回调函数使用它来增加它的每次调用)。
W3schools 的评论不完整。大多数时候,变量会在函数结束时被清理(不一定是立即,而是在下次运行垃圾回收时)。但这只是因为大多数时候不再有对这些变量的引用。
但是,由于 javascript 支持函数作为第一个 class 对象,它也支持闭包。当你有这样一行时:
$(document).on('mousedown', function(){console.log('down: ', x++);});
...您正在创建闭包。该闭包是新函数,加上定义它的词法环境。它有一个对 x
的引用,因此即使 a
完成解析,x
也不会被垃圾回收。稍后调用该函数时,它仍然可以很好地访问闭包变量。
x
仍然有可能被垃圾回收,但前提是所有引用它的闭包也被垃圾回收。在这种情况下,您可以通过注销 mouseup 和 mousedown 事件并取消间隔来实现。
所以...我来自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”或 NaN 或 null,因为 x 应该在范围的末尾被删除,但似乎所有三个回调都永远引用它......为什么?它是一种新行为还是自旧 JS 版本以来就这样工作?我找不到答案。
函数可以访问 x,因为您在可访问的范围内为它们提供了该变量。它计数是因为在 javascript 中你没有给出实际值而只是对它的引用,所以你所有的回调仍然引用 a() 函数内的 x 。因为它仍然被引用 javascript 的垃圾收集器不会删除它,因为它认为它仍然是 'in use',它确实是(因为你的回调函数使用它来增加它的每次调用)。
W3schools 的评论不完整。大多数时候,变量会在函数结束时被清理(不一定是立即,而是在下次运行垃圾回收时)。但这只是因为大多数时候不再有对这些变量的引用。
但是,由于 javascript 支持函数作为第一个 class 对象,它也支持闭包。当你有这样一行时:
$(document).on('mousedown', function(){console.log('down: ', x++);});
...您正在创建闭包。该闭包是新函数,加上定义它的词法环境。它有一个对 x
的引用,因此即使 a
完成解析,x
也不会被垃圾回收。稍后调用该函数时,它仍然可以很好地访问闭包变量。
x
仍然有可能被垃圾回收,但前提是所有引用它的闭包也被垃圾回收。在这种情况下,您可以通过注销 mouseup 和 mousedown 事件并取消间隔来实现。