Javascript:没有名字的对象会发生什么?

时间:2013-06-28 13:51:14

标签: javascript

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

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事件。生成的对象在哪里存在并且可以访问它?

2 个答案:

答案 0 :(得分:5)

如果没有指向此对象的引用(即您没有将它分配给任何变量或任何属性的值),那么就无法访问它,实际上它并不像垃圾一样生存收藏家可以立即收回这段记忆。

答案 1 :(得分:2)

简短的回答是 no ,对象不会在你无法触及的某个地方保存。比特生活是活的:如果你掌握了基础知识,事实就更复杂了,但不是很多。

更新
响应您的更新:在某种程度上,您是对的。回调是对MyObject.prototype.alert的引用,您使用this.alert访问了该引用,但该函数对象正由构造函数原型引用,并且无论如何都不能进行GC。 实例本身不参与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或调用上下文可以根据调用函数的方式和位置而改变的原因。 see here for more on ad-hoc context determination

我甚至会为你做得更好:

/*assume your code is here*/
new MyConstructor().alert = function(){ alert('I am deaf');};
MyConstructor.prototype.alert = 'foo';
$('#button').click();

猜猜是什么,点击事件提醒“我听说过”一样,原型甚至没有涉及,更不用说实例了。
如果MyConstructor超出范围,click事件仍然可以正常工作,因为GC仍然会看到对范围不在范围之外的警报功能对象的引用。其他一切都可用于GC',但是......


JS垃圾收集器(GC)是一个标记和刷卡GC。当JS引擎遇到您的语句时,它 分配存储对象所需的内存。到达下一个语句时,该对象可能仍在内存中 不时地,GC X检查它在内存中看到的所有对象,并尝试找到仍然可访问的对该对象的所有引用。当遇到刚刚在该语句中创建的对象文字但未分配任何引用时,该对象将被标记为垃圾回收。
GC下次刷入标记对象的业务时,该对象将从内存中删除。

当然,对于所有引擎来说,这并非完全正确。假设你的陈述是在IIFE中写的,它返回了一个函数:

var foo = function()
{
    {name: 'bar'};
    return function()
    {
        return 'foobar';
    };
}());

某些引擎只是将IIFE的整个范围保留在内存中,并且只有当IIFE的返回值超出范围(标记为GC)时才释放该范围的内存。其他引擎,比如上次我检查的V8,实际上会标记外部范围的那些未被其返回值引用的对象/变量。
虽然,考虑一下,它可能不适用于这种情况,因为GC甚至可能在IIFE返回之前启动......但总的来说,这只是挑选。

还有一个逻辑OR的问题需要考虑:

var name = (mayNotExist || {name:'default'}).name;

在这种情况下,如果存在mayNotExist ,则由于JS对表达式的短路评估,甚至都不会创建对象文字。

关于此事的几个链接: