【问题标题】:Javascript: What happens to objects that don't have a name?Javascript:没有名称的对象会发生什么?
【发布时间】:2013-06-26 07:40:15
【问题描述】:

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

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

【问题讨论】:

  • 不。创建对象并收集垃圾。就像那些"use strict"; 字符串一样。我觉得一些 JS 引擎甚至可以避免创建
  • 其他人对此提出质疑,但删除了他们的评论。您的第一个示例是否明确定义了您认为的对象,还是只是一个块、一个标签和一个字符串?
  • 我已经更新了我的答案,以扩展您的更新(关于在构造函数中绑定事件处理程序,我可以补充一下,这通常不是最好的主意(

标签: javascript


【解决方案1】:

如果没有指向该对象的引用(也就是说,您没有将它分配给任何变量或任何属性的值),那么就无法访问它,实际上它不是垃圾收集器可以立即回收此内存。

【讨论】:

  • 我喜欢认为它已经逃脱并以羔羊为生。
  • @Yatrix 我认为这是“在羔羊上”,但“在羔羊上生活”听起来更美味!
  • @MattHarrison 呵呵。我从来没有上过羊羔,但如果我上过羊羔,我希望我能带上羊羔。
【解决方案2】:

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

更新:
回应您的更新:在某种程度上,您是对的。回调是对MyObject.prototype.alert 的引用,您使用this.alert 访问它,但该函数对象被构造函数原型引用,并且无论如何都不能被GC'ed。 instance 本身不涉及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'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 对表达式的短路求值,甚至永远不会创建对象字面量。

关于此事的几个链接:

【讨论】:

  • 感谢您提供非常完整的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-31
  • 1970-01-01
  • 2023-04-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多