简短的回答是否定的,该对象不会在您无法到达的内存中保持活动状态。生活是真实的:如果你掌握了基础知识,真相会稍微复杂一些,但不会复杂很多。
更新:
响应您的更新:在某种程度上,您是对的。回调是对 的引用MyObject.prototype.alert
,您使用 访问它this.alert
,但该函数对象被构造函数原型引用,并且无论如何都不能被 GC'ed。实例本身不涉及函数本身,因此alert
可以安全地进行 GC。
可以这样想:
MyConstructor.prototype.alert = 0x000123;//some memory address
||
\/
0x000123 = [object Function];
函数对象本身并不直接附加到任何东西上,它漂浮在内存中,并被原型引用。创建实例时:
new MyConstructor().alert;
解决如下:
[new MyConstructor instance] allocated at e.g 0x000321
||
\\
\=>[alert] check for alert @instance -> not found
\\
\=> check prototype, yield 0x000123 <-- memory address, return this value
所以在执行语句时:
$("button").click(this.alert);
this.alert
是解析为 的表达式0x000123
。也就是说,jQ的click
方法(函数对象)只接收函数对象的内存地址alert
。实例,或者实际上是构造函数根本不涉及。这就是为什么this
或调用上下文可以根据调用函数的方式和位置而改变的原因。有关临时上下文确定的更多信息,请参见此处
我什至会给你一个更好的:
/*assume your code is here*/
new MyConstructor().alert = function(){ alert('I am deaf');};
MyConstructor.prototype.alert = 'foo';
$('#button').click();
你猜怎么着,点击事件警报“我听说了”都一样,甚至没有涉及原型,更不用说实例了。
如果MyConstructor
超出范围,该click
事件仍然可以正常工作,因为 GC 仍然会看到对尚未超出范围的警报函数对象的引用。其他所有东西都可用于 GC'ing,虽然......
JS 垃圾收集器 (GC) 是一个标志和滑动 GC。当 JS 引擎遇到您的语句时,它会分配存储对象所需的内存。当到达下一条语句时,该对象可能仍在内存中。
GC X 时不时地检查它在内存中看到的所有对象,并尝试找到对该对象仍可访问的所有引用。当遇到刚刚在该语句中创建的对象字面量,但没有分配对的引用时,该对象被标记为垃圾回收。
下次 GC 处理其刷标记对象的业务时,该对象将从内存中删除。
当然,这并不完全适用于所有引擎。假设您的语句是用 IIFE 编写的,它返回一个函数:
var foo = function()
{
{name: 'bar'};
return function()
{
return 'foobar';
};
}());
一些引擎只是将 IIFE 的整个范围保留在内存中,并且仅在 IIFE 的返回值超出范围(标记为 GC)时为该范围释放内存。其他引擎,比如我上次检查的 V8,实际上会标记那些外部范围的对象/变量,这些对象/vars 没有被它的返回值引用。
不过,仔细想想,它可能不适用于这种情况,因为 GC 甚至可能在 IIFE 返回之前就开始了......但总的来说,这只是吹毛求疵。
还有逻辑或的问题需要考虑:
var name = (mayNotExist || {name:'default'}).name;
在这种情况下,如果mayNotExist
确实存在,则对象字面量甚至永远不会被创建,这要归功于 JS 对表达式的短路评估。
关于此事的几个链接: