4

如果我执行以下操作(在全局范围内):

var myObject = {name: "Bob"};

我有办法指向内存中的那个对象(即字符串标识符“myObject)”。我可以打开控制台并输入:myObject.name控制台将响应:

"Bob"

现在,如果我只输入:

{name: "Jane"};

我正在某处创建该对象,我猜它会继续存在于某个范围内。有什么办法可以找到吗?它是否存在于window某个通用商店的某个地方?

编辑:有人说它只会收集垃圾。

那么这个例子怎么样:

var MyObject = function(){
    $("button").click(this.alert);
}

MyObject.prototype.alert = function(){
    alert("I heard that!")
}

new MyObject();

它不能被垃圾回收,因为它的回调绑定到一个 DOM 事件。生成的对象在哪里,可以访问吗?

4

2 回答 2

5

如果没有指向该对象的引用(即您没有将其分配给任何变量或任何属性的值),那么就无法访问它,实际上它没有生命,因为垃圾收集器可以回收这个记忆立刻。

于 2013-06-28T13:52:43.910 回答
2

简短的回答是否定的,该对象不会在您无法到达的内存中保持活动状态。生活是真实的:如果你掌握了基础知识,真相会稍微复杂一些,但不会复杂很多。

更新:
响应您的更新:在某种程度上,您是对的。回调是对 的引用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 对表达式的短路评估。

关于此事的几个链接:

于 2013-06-28T13:57:19.793 回答