从类函数中删除类变量

时间:2012-08-08 13:06:34

标签: javascript javascript-events

我正在创建一个将被重复多次的类,为了节省内存,我需要彻底删除它。基本上我需要尽可能访问它的包含变量。

以下是示例:

function example(){
  this.id=0;
  this.action=function(){alert('tost');}
  this.close=function(){ delete this;}
}

var foo=new example();

我的问题是:

如何从示例功能中访问 foo变量,以便将其删除?

3 个答案:

答案 0 :(得分:1)

window.foo将访问该全局变量。

this.close=function(){ delete window.foo; }

但是,我记得有something fishy with global variables, delete and window,所以您可能不想这样做,只需使用window.foo = null;

如果您想访问另一个函数中定义的变量,您需要阅读this SO question的答案。

由于您希望允许垃圾收集器释放该对象,因此您需要确保没有对该对象的引用。这可能非常棘手(即不可能),因为操纵对象的代码可以通过全局变量和局部变量以及属性对其进行多次引用。

你可以通过创建一个访问它的代理来阻止对该对象的直接引用,遗憾的是javascript并不能很好地支持动态getter和setter(也称为catch-alls)(在某些浏览器上你可能会实现它, see this SO question),因此您无法轻松地重定向所有字段和方法(无论如何只是字段)访问底层对象,尤其是当底层对象添加了许多字段并动态删除它时(即this.anewfield = anewvalue)。

这是一个smiple代理(jsfiddle.net上的代码):

function heavyobject(destroyself, param1, param2) {
    this.id=0;
    this.action=function(){alert('tost ' + param1 + "," + param2);};
    this.close=function(){ destroyself(); }
}

function proxy(param1, param2) {
    object = null;
    // overwrites object, the only reference to
    // the heavyobject, with a null value.
    destroyer = function() { object = null; };
    object = new heavyobject(destroyer, param1, param2);
    return function(fieldname, setvalue) {
        if (object != null) {
            if (arguments.length == 1)
                return object[fieldname];
            else
                object[fieldname] = setvalue;
        }
    };
}
var foo = proxy('a', 'b');
alert(foo("action")); // get field action
foo("afield", "avalue"); // set field afield to value avalue.
foo("action")(); // call field action
foo("close")(); // call field close
alert(foo("action")); // get field action (should be 'undefined').

它通过返回一个函数来工作,该函数在使用单个参数调用时,在包装对象上获取字段,并且在使用两个参数调用时设置字段。它的工作原理是确保对重对象的唯一引用是object函数中的proxy局部变量。

heavyobject中的代码必须从不泄漏this(永远不会返回它,永远不会返回一个持有对var that = this的引用的函数,永远不会将它存储到另一个变量的字段中),否则可能会创建一些指向重对象的外部引用,阻止其被删除。

如果heavyobject的构造函数从构造函数(或构造函数调用的函数)中调用destroyself(),则它不会产生任何影响。

另一个更简单的代理,它将为您提供一个空对象,您可以在其上添加字段,读取字段和调用方法。我很确定使用这个,没有外部参考可以逃脱。

代码(也在jsfiddle.net上):

function uniquelyReferencedObject() {
    object = {};
    f = function(field, value) {
        if (object != null) {
            if (arguments.length == 0)
                object = null;
            else if (arguments.length == 1)
                return object[field];
            else
                object[field] = value;
        }
    };
    f.destroy = function() { f(); }
    f.getField = function(field) { return f(field); }
    f.setField = function(field, value) { f(field, value); }
    return f;
}
// Using function calls
o = uniquelyReferencedObject();
o("afield", "avalue");
alert(o("afield")); // "avalue"
o(); // destroy
alert(o("afield")); // undefined
// Using destroy, getField, setField
other = uniquelyReferencedObject();
other.setField("afield", "avalue");
alert(other.getField("afield")); // "avalue"
other.destroy();
alert(other.getField("afield")); // undefined

答案 1 :(得分:1)

事实是你在Javascript中无法删除对象

然后使用删除运算符,它只接受某个对象的属性。 因此,当您使用删除时,通常您必须传递类似obj.p的内容。然后你传递一个变量名实际上这意味着'全局对象的属性',而delete pdelete window.p相同。不确定delete this内部发生了什么,但结果浏览器只是跳过它。

现在,我们用delete实际删除了什么?我们删除对象的引用。它意味着对象本身仍然存在于记忆中。要消除它,您必须删除对具体对象的所有引用。 Everythere - 来自其他对象,来自闭包,来自事件处理程序,链接数据,所有这些。但是对象本身doest有关于它的所有这些引用的信息,所以没有办法从对象本身删除对象。 看看这段代码:

var obj = <our object>;
var someAnother = {
       ...
       myObjRef: obj
       ...
 }
var someAnotherAnother = {
       ...
       secondRef : obj
       ...
}

要消除记忆中的obj,您必须删除someAnother.myObjRef someAnoterAnother.secondRef。你只能从了解所有这些部分的程序部分来做到这一点。

如果我们可以拥有任何数量的引用,那么我们如何删除某些东西呢?有一些方法可以解决这个问题:

  • 在程序中只有一个点,这个对象将被引用。事实上 - 我们的计划中只有一个参考。然后我们删除它 - 对象将被垃圾收集器杀死。这是上面描述的“代理”方式。这有它的缺点(还没有语言本身的支持,以及将酷和好obj.x=1更改为obj.val('x',1)的必要性。而且,这不太明显,事实上你将所有对obj的引用更改为引用代理。代理将始终保留在内存而不是对象。根据对象大小,对象数量和实现,这可以给你一些利润。甚至可以使事情变得更糟。例如,如果你的对象的大小接近代理的大小本身 - 你将得不到任何价值。

  • 在每个地方添加你使用一个对象的代码,该代码将删除对该对象的引用。它使用起来更加清晰和简单,因为如果你在某个地方调用obj.close() - 你已经知道了删除它所需的一切。只是代替obj.close()杀死了对它的引用。通常 - 将此引用更改为另一个:

      var x = new obj; //now our object is created and referenced
      x = null;// now our object **obj** still im memory 
      //but doest have a references to it 
      //and after some milliseconds obj is killed by GC...
    
      //also you can do delete for properties
      delete x.y; //where x an object and x.y = obj
    

    但是使用这种方法你必须记住引用可能是非常难以理解的地方。例如:

      function func() {
         var x= new obj;// our heavy object
         ...
         return function result() {
             ...some cool stuff..
         }
      }
    

    引用存储在result函数的闭包中,当你引用result时,obj将保留在内存中。

  • 很难想象对象本身很重,最现实的情况 - 你里面有一些数据。在这种情况下,您可以向对象添加清理函数,该函数将清除此数据。假设你有一个gigant缓冲区(例如数组)作为对象的属性,如果你想释放内存 - 你可以清除这个缓冲区仍然在内存中有几十个字节的对象。并且记得将你的函数放到原型中以保持实例的小。

答案 2 :(得分:0)

以下是有关JavaScript删除操作符的一些非常详细信息的链接。

http://perfectionkills.com/understanding-delete/