2012-08-08 51 views
0

我正在創建一個將被重新創建多次的類,爲了節省內存,我需要徹底刪除它。基本上我需要訪問它的包含變量,如果可能的話。從類函數中刪除類變量

這裏的例子:

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

var foo=new example(); 

我的問題是:

我怎樣才能從例如函數中可以訪問的FOO變量這樣我就可以刪除嗎?

回答

1

window.foo將訪問該全局變量。

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

不過,我記得有something fishy with global variables, delete and window,所以你可能想不這樣做,而只需使用window.foo = null;例如。

如果您想訪問另一個函數中定義的變量,您需要閱讀this SO question的答案。

因爲你想要的是允許垃圾收集器釋放該對象,你需要確保沒有引用留給對象。這可能非常棘手(即不可能),因爲操縱對象的代碼可以通過全局和局部變量以及屬性對其進行多次引用。

您可以通過創建一個代理來訪問它,但不幸的是,JavaScript不支持動態獲取器和設置器(也稱爲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'). 

它的工作原理是返回一個函數,當用一個參數調用,獲取被包裝的對象上的字段,當有兩個參數調用設置一個字段。它的工作原理是確保對重對象的唯一引用是proxy函數中的object局部變量。

在heavyobject代碼必須從未泄漏this(永遠不會返回它,不會返回保持到var that = this的基準的功能,從來沒有將其存儲到另一個變量的場),否則某些外部參考可以創建將指向重金屬,防止其刪除。

如果重對象的構造函數在構造函數中(或來自構造函數調用的函數)調用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 
+0

但是,如果它不是一個全局變量? – DerWaldschrat 2012-08-08 13:10:13

+0

,這不會幫助我,因爲變量foo可以通過許多名稱來定義,例如:var foo = new example; var test = new example();在你的情況下,我不能關閉測試變量 – volchkov 2012-08-08 13:11:01

+0

其一個解決方案,但稱它有點不方便,所以我想出了一個更簡單的解決方案。只要我將變量定義爲全局變量,我可以通過window ['foo']訪問它,所以我所做的就是檢查範圍上的所有變量,如果它們中的任何一個具有窗口[i] .id和window [i] .action我刪除它們 – volchkov 2012-08-08 14:07:55

0

下面是一些非常詳細信息的鏈接,JavaScript的delete操作符。

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

+0

據說有刪除不能刪除函數,所以我需要訪問foo變量來刪除它。那就是我正在試圖找出如何去做 – volchkov 2012-08-08 13:17:33

1

的事實是,你不能在Javascript中刪除對象

然後您使用刪除運算符,它只接受某個對象的屬性。 所以,當你使用刪除,一般你必須通過它像obj.p。然後你只傳遞一個變量名,實際上這意味着'全局對象的屬性',並且delete pdelete window.p相同。不確定在delete this內部發生了什麼,但結果瀏覽器只是跳過它。

現在,我們實際上用delete刪除了什麼?我們刪除對象的引用。這意味着對象本身在內存中仍然存在。要消除它,您必須刪除全部對具體對象的引用。 Everythere - 來自其他對象,閉包,事件處理程序,鏈接數據,所有這些。但是對象本身也有關於它的所有引用的信息,所以沒有辦法從對象本身中刪除對象。 看看這段代碼:

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

爲了消除內存OBJ必須刪除someAnother.myObjRefsomeAnoterAnother.secondRef。你只能從知道它們的程序部分來完成它。

而我們如何刪除一些東西,如果我們可以有任何數量的引用everythere?有一些方法可以解決這個問題:

  • 在程序中只做一個點,從那裏引用這個對象。事實上 - 我們的程序中只有一個參考。然後我們刪除它 - 對象將被垃圾收集器殺死。這是上面描述的'代理'方式。這有它的缺點(語言本身沒有支持,並且需要改變cool和nice obj.x=1obj.val('x',1)。此外,這並不明顯,實際上你將所有對obj的引用改爲對proxy的引用,並且代理將始終保留在內存而不是對象,根據對象的大小,對象的數量和實現情況,這可以給你帶來一些利潤,甚至會讓事情變得更糟,例如,如果你的對象的大小接近代理本身的大小 - 你就沒有價值。

  • 添加到每個地方你使用一個對象,這將刪除引用此對象的一個​​代碼更清晰,使用簡單,因爲如果你調用一個obj.close()在一些地方 - 你已經知道你需要的一切東西刪除它,而不是obj.close()殺死refernce它。在一般 - 該參考更改爲另一:

    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 somethere參考。

  • 很難想象物體本身沉重,最現實的情況 - 你有什麼數據在裏面。在這種情況下,您可以將清理函數添加到將清理此數據的對象。比方說,你有一個巨大的緩衝區(例如數組數組)作爲對象的一個​​屬性,如果你想釋放內存 - 你可以清除這個緩衝區中仍有對象的內存爲幾十個字節。並且記住把你的函數放到原型中以保持實例的小。