0

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

这是示例:

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

var foo=new example();

我的问题是:

如何从示例函数中访问foo 变量以便删除它?

4

3 回答 3

1

事实是您不能在 Javascript 中删除对象。

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

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

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

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

如果我们到处都有任意数量的引用,我们如何删除一些东西?有一些方法可以解决这个问题:

  • 从那里只在程序中做一个点,这个对象将被引用。事实上 - 我们的程序中只有一个引用。然后我们删除它——对象将被垃圾收集器杀死。这是上面描述的“代理”方式。这有其缺点(语言本身尚不支持,并且需要将cool and nice 更改obj.x=1obj.val('x',1)。此外,这不太明显,实际上您将对obj 的所有引用更改为对proxy 的引用。而proxy 将始终保留在内存中对象。根据对象的大小、对象的数量和实现,这可以给你带来一些利润或不给你一些利润。或者甚至让事情变得更糟。例如,如果你的对象的大小接近代理本身的大小 - 你将一文不值。

  • 在每个使用对象的地方添加一个代码,该代码将删除对该对象的引用。它使用起来更加清晰和简单,因为如果您obj.close()在某个地方调用 a - 您已经知道删除它所需的一切。而不是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函数的闭包中,当您对某个地方有引用时,obj 将保留在内存中result

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

于 2012-08-10T12:02:30.943 回答
1

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

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

但是,我记得全局变量 delete 和 window 有一些可疑之处,因此您可能希望不这样做,并简单地使用window.foo = null;例如。

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

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

您可以通过创建代理来访问它来防止直接引用该对象,不幸的是,javascript 不支持动态 getter 和 setter(也称为 catch-alls)很好(在某些浏览器上您可能会实现它,请参阅这个 SO question) ,因此您不能轻松地将所有字段和方法(无论如何都只是字段)访问重定向到底层对象,特别是如果底层对象添加了许多字段并动态地从中删除(即this.anewfield = anewvalue)。

这是一个简单的代理(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

重对象中的代码绝不能泄漏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
于 2012-08-08T13:09:28.243 回答
0

这是一个关于 JavaScript 删除运算符的一些非常详细的信息的链接。

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

于 2012-08-08T13:13:11.890 回答