2013-01-20 105 views
2

我想知道如何正確「清除」一個對象實例。 使用下面的代碼,內部setInterval()即使在父實例被「清除」之後仍將繼續運行。如何在javascript中刪除/清除/忘記對象實例?

// simple Class 
var aClass = function(){ 
    return { 
     init: function(){ 
      console.log("aClass init()") 
      setInterval(this.tick, 1000); 
      // note: we're not storing the ref 
     }, 
     tick: function(){ 
      console.log("aClass tick"); 
     } 
    } 
} 

// instantiate the class 
var inst = new aClass(); 
inst.init(); 


// try to forget the instance 
function test(){ 
    console.log("test() 1 inst:", inst); 

    inst = null; 

    console.log("test() 2 inst:", inst); 
} 

// run for a while, then call test() 
setTimeout(test, 4000); 

輸出:

aClass init() 
aClass tick 
aClass tick 
aClass tick 
test() 1 inst: {.....} 
test() 2 inst: null 
aClass tick 
aClass tick ... 

問題是, 「ACLASS嘀」 消息繼續試驗後打印()。

想法?

+3

'setInterval'及其處理程序無關,與你的對象。 – VisioN

+3

@VisioN - OP的觀點是,如果對象的引用保持在閉包中,則該對象不會真的被「刪除」。 – nrabinowitz

+0

該對象被刪除,inst在第二個控制檯日誌中爲空。當用作setInterval的參數時,函數節點被複制。 – HMR

回答

3

您的實例將被保存在內存中,因爲你傳遞給setInterval功能被保存在內存中,並具有對它的引用。該功能由瀏覽器的活動間隔定時器列表引用。

你需要記住的間隔手柄:

this.intervalHandle = setInterval(this.tick, 1000); 

......再後來,當你下降到inst你參考,你要告訴它:

inst.cleanup(); 
inst = null; 

...在inst.cleanup

clearInterval(this.intervalHandle); 

這樣的話,瀏覽器會雷莫請參考您傳遞給setInterval的函數,這意味着函數將符合垃圾回收的條件(根據您的代碼,沒有其他引用)。這意味着參考文獻必須將您的實例發佈,因此如果沒有其他未完成的對該實例的引用存在,則它符合垃圾回收的條件。

+0

感謝您的超級解釋。這正是我所擔心的。真的沒有辦法「強制刪除」它嗎? – jorgenskogmo

+1

@jorgenskogmo:不,垃圾收集環境的本質是,「刪除」東西的唯一方法是確保沒有未完成的引用,並讓GC完成它的工作。在這種情況下,如上所述,這很容易。如果你能*強制它,那隻會引入新的問題(由於引用了某些你「被迫」出內存的東西而引起的錯誤)。 –

0

這是因爲瀏覽器本身保持跟蹤setIntervalsetTimeout計劃的所有功能。 (否則,你不得不在某處存儲函數,在大多數情況下這會非常惱人)。而且你的函數有一個方法的引用,所以這個方法仍然存在。但我懷疑其餘的東西會被扔掉,儘管這有點難以證明。

如果你打算取消預定這樣的功能,你需要明確這樣做:

this.interval = setInterval(function, 4000); 

// and then later, in some `destroy()` method 
clearInterval(this.interval); 

而且,順便說一句,你應該很少需要從構造函數返回一個大哈希那樣的!與原型工作,而不是:

var SomeClass = function() { 
    // ... 
}; 

SomeClass.prototype.method = function() { 
    console.log('hello from', this); 
}; 
+0

關於「將參數存儲到setInterval()」 - 是的。謝謝。關於原型vs構造函數> return {},這似乎是關於編碼「樣式」或習慣 - 還是真的有一個理由而不是另一個呢? – jorgenskogmo

+0

大多數習慣存在的原因是:在這種情況下,每次創建對象時都要創建_entire class_的新副本。 – Eevee

0

我的猜測是,你ACLASS的情況已經一去不復返了,因爲沒有辦法訪問任何它的性能,但在初始化作爲一個參數給setInterval使用時刻度功能被複制。

var tickfunction=null; 
var aClass = function(){ 
    return { 
     init: function(){ 
      console.log("aClass init()") 
      tickfunction = this.tick; 
     }, 
     tick: function(){ 
      console.log("aClass tick"); 
     } 
    } 
} 

// instantiate the class 
var inst = new aClass(); 
inst.init(); 

// try to forget the instance 
console.log("test() 1 inst:", inst); 
inst = null; 
console.log("test() 2 inst:", inst);// its null isn't it? 
console.log("the tickfunction:",tickfunction); 

爲了說明該功能被複制:

function toInterval(){ 
    console.log("orig"); 
} 
setInterval(toInterval,1000);//prints orig every second 
toInterval=function(){ 
    console.log("changed it"); 
} 
toInterval();//prints changed it