JavaScript:通过类方法创建和销毁类实例

Posted

技术标签:

【中文标题】JavaScript:通过类方法创建和销毁类实例【英文标题】:JavaScript: Create and destroy class instance through class method 【发布时间】:2014-02-02 19:57:43 【问题描述】:

我试图弄清楚如何通过类方法删除对象。我希望能够创建一个具有从内存中释放对象的销毁方法的类。到目前为止,我所做的研究还没有定论。我知道垃圾收集最终会处理该对象,但我想要一种更明确的方式来销毁它。这可能吗?

// class constructor
var class = function () 
     this.destroy = function () ;
;

// instance
var instance = new class();
instance.destroy();
console.log(instance); // should be null or undefined

【问题讨论】:

How to have an instance delete itself from within a prototype function is javascript 的可能重复项 这种问题似乎来自对对象实例如何生存和死亡的误解。这根本不是 JS 的工作方式,但这并不意味着它是一个限制。这意味着事情需要以不同的方式完成。那么你在这里的真正目标是什么? 我的目标是快速删除对象,包括事件处理程序以及由于创建对象而创建的任何内容。 @尼克C 看看我的回答,我想你会得到你想要的。 我不是SO的常客,所以这么晚才遇到。我经常看到人们试图确定类的范围,但使用 document.head.appendChild() 将其加载到文档中。这将注册,并且 eval() - 即使 eval.call(,js) 将使用窗口范围来查找类。相反,不要将它添加到文档中(如果你是的话),而是使用类似 eval.call(,'class myclass (function() return new MyClass())()') 来评估整个类.这不应该使用窗口,您可以随时替换 MyClass。 【参考方案1】:

1- 无法在 javascript 中实际销毁对象,但使用delete,我们可以从对象中删除引用:

var obj = ;
obj.mypointer = null;
delete obj.mypointer;

2- 关于delete 关键字的重要一点是,它实际上并没有销毁对象,但如果仅在删除对该对象的引用之后,内存中没有其他指向同一对象的引用,即对象将被标记为可收藏。 delete 关键字删除引用但不 GC 实际对象。这意味着如果您对同一个对象有多个引用,则该对象将在您删除所有指向的引用后立即被收集。

3- 当我们想要确保不会留下任何内存泄漏时,还有一些技巧和解决方法可以帮助我们。例如,如果您有一个包含多个对象的数组,而没有任何其他指向这些对象的引用,那么如果您重新创建该数组,所有这些对象都将被杀死。例如,如果您有 var array = [, ] 覆盖数组的值,如 array = [] 将删除对数组内两个对象的引用,这两个对象将被标记为可收集。

4- 对于您的解决方案,最简单的方法就是:

var storage = ;
storage.instance = new Class();
//since 'storage.instance' is your only reference to the object, whenever you wanted to destroy do this:
storage.instance = null;
// OR
delete storage.instance;

如上所述,设置storage.instance = nulldelete storage.instance 就足以删除对对象的引用并允许GC 清理它。不同之处在于,如果将其设置为null,则存储对象仍然有一个名为 instance 的属性(值为 null)。如果你delete storage.instance 则存储对象不再具有名为实例的属性。

破坏方法怎么样??

这里的矛盾点是,如果您在销毁函数中使用instance.destroy,您将无法访问实际的instance 指针,并且它不会让您删除它。

唯一的办法是将引用传递给destroy函数,然后将其删除:

// Class constructor
var Class = function () 
     this.destroy = function (baseObject, refName) 
         delete baseObject[refName];
     ;
;

// instanciate
var storage = ;
storage.instance = new Class();
storage.instance.destroy(object, "instance");
console.log(storage.instance); // now it is undefined

但是如果我是你,我会坚持第一个解决方案并像这样删除对象:

storage.instance = null;
// OR
delete storage.instance;

哇,太多了:)

【讨论】:

@vsync 如果它没有附加到任何对象或变量,那么一旦它运行完任何代码就会被收集。例如,如果您执行(new SomeObject).doSomething),那么它将在执行完doSomething 后被收集。如果该对象有一个setTimeout 调用或任何其他触发异步逻辑的东西,那么 SomeObject 在其他任务完成之前不会被收集(除非这些任务不包含对 SomeObject 实例或任何其他属于 SomeObject 的引用实例)。 @vsync 假设doSomething 方法设置了一个setInterval,它执行console.log(this),那么setInterval 将永远运行并且SomeObject 将永远不会被收集,除非该间隔具有将clearInterval 在某个时候。基本上,如果一个对象没有运行(或正在运行)的代码,也没有对它的引用,它将被收集。 这个答案不正确。 javascript 中的delete keyword 从对象中删除属性。它不直接释放内存,也不破坏对象。如果是这样,那么在调用 delete 之前将引用设置为 null 是没有意义的。 @DavidMills 感谢您让我知道我多年前的这个错误答案,我做了一些更改,请您检查一下以确保它现在是否有意义? storage.instance的例子中,如果你想让GC清理instance对象,那么或者设置storage.instance = null或者 i> delete storage.instance 足以删除对对象的引用并允许它被 GC 清理。不同之处在于,如果将其设置为null,那么storage 对象仍然有一个名为instance 的属性(值为null)。如果您 delete storage.instancestorage 对象不再具有名为 instance 的属性。【参考方案2】:

没有。 JavaScript 会自动进行垃圾回收;只有当 GC 决定运行并且对象符合回收条件时,才会回收对象的内存。

既然这将根据需要自动发生,那么显式回收内存的目的是什么?

【讨论】:

我想快速删除创建对象时创建的事件处理程序、引用等。 @user699242:再说一遍,为什么?如果除了对象之外没有人引用这些东西,那么回收对象也将允许回收这些东西。除了“丢失”对对象的所有引用之外,您无需执行任何操作。为什么要手动操作? 我猜“失去所有对对象的引用”对我来说是模棱两可的。什么时候发生?对不起,这一直让我很困惑 换句话说,我是否需要做任何事情来“释放参考”。例如将指针设置为 null 或... 枚举的可能性太多了,但总的来说“将那个东西设置为null”会起作用。然而,这是你应该更好地处理的事情,因为它可以在内存泄漏到崩溃镇之间产生差异。你真的必须尝试那样泄漏,但是......【参考方案3】:

您只能手动删除对象的属性。因此:

var container = ;

container.instance = new class();

delete container.instance;

但是,这不适用于任何其他指针。因此:

var container = ;

container.instance = new class();

var pointer = container.instance;

delete pointer; // false ( ie attempt to delete failed )

此外:

delete container.instance; // true ( ie attempt to delete succeeded, but... )

pointer; // class  destroy: function() 

因此在实践中,删除仅对删除对象属性本身有用,而不是从内存中删除它们指向的代码的可靠方法。

手动指定的destroy 方法可以取消绑定任何事件侦听器。比如:

function class()
  this.properties =  /**/ 

  function handler() /**/ 

  something.addEventListener( 'event', handler, false );

  this.destroy = function()
    something.removeEventListener( 'event', handler );
  

【讨论】:

这不是 = void 0;左手分配无效? 你说得对。这也是一个非常愚蠢的想法,因为即使它确实有效,它所能做的只是由于缺少指针而导致错误。

以上是关于JavaScript:通过类方法创建和销毁类实例的主要内容,如果未能解决你的问题,请参考以下文章

Effective Java阅读笔记——创建和销毁对象

读书笔记《Effective Java》——创建和销毁对象

java中静态成员变量、实例变量、局部变量何时创建、何时销毁?

Java——变量

Effective Java读书笔记创建和销毁对象:考虑使用静态工厂方法代替构造器

java学习笔记:变量类型