2009-07-09 11 views
24

Perché non posso utilizzare setTimeout in un oggetto javascript?Come utilizzare "setTimeout" per richiamare l'oggetto stesso

Message = function() { 

    ... 
    ...   

    this.messageFactory = ... 
    this.feedbackTag = document.getElementById('feedbackMessages'); 

    this.addInfo = function (message) { 
     var info = this.messageFactory.createInfo(message); // create a div 
     this.feedbackTag.appendChild(info); 

     setTimeout('this.feedbackTag.removeChild(info)', 5000); 
     // why in here, it complain this.feedbacktag is undefined ?????? 

    }; 
} 

Grazie per Steve`s Solution, ora funzionerà se il codice è la seguente ... perché il 'questo' prima era in realtà che punta alla funzione all'interno setTimeOut, non può Messaggio rearch.

Message = function() { 

    ... 
    ...   

    this.messageFactory = ... 
    this.feedbackTag = document.getElementById('feedbackMessages'); 

    this.addInfo = function (message) { 
     var info = this.messageFactory.createInfo(message); // create a div 
     this.feedbackTag.appendChild(info); 

     var _this = this; 
     setTimeout(function() { _this.feedbackTag.removeChild(info); }, 5000); 

    }; 
} 

Ma perché doesn`t funziona se facciamo questo:

Message = function() { 

    ... 
    ...   

    this.messageFactory = ... 
    this.feedbackTag = document.getElementById('feedbackMessages'); 
    // public function 
    this.addInfo = function (message) { 
     var info = this.messageFactory.createInfo(message); // create a div 
     this.feedbackTag.appendChild(info); 

     delayRemove(info); 

    }; 
    // private function 
    function delayRemove(obj) { 
     var _this = this; 
     setTimeout(function() { _this.feedbackTag.removeChild(info); }, 5000); 
    } 
} 
+0

possibile duplicato di [Come accedere al corretto 'this'/contesto all'interno di un callback?] (Http://stackoverflow.com/q/20279484/1048572) – Bergi

+0

Duplicati: [setTimeout() all'interno della classe JavaScript che utilizza" questo "] (Http://stackoverflow.com/questions/5911211/settimeout-inside-javascript-class-using-this) e [Utilizzo di setTimeout() all'interno di una funzione di classe JavaScript] (http://stackoverflow.com/questions/ 6997921/using-settimeout-in-a-javascript-class-function) – handle

risposta

84

Provare a sostituire questa linea:

setTimeout('this.feedbackTag.removeChild(info)', 5000); 

con queste due righe:

var _this = this; 
setTimeout(function() { _this.feedbackTag.removeChild(info); }, 5000); 

Nota:

Non passare mai setTimeout una stringa, poiché invoca lo eval (che è consigliabile utilizzare solo quando necessario). Invece, passare setTimeout un riferimento funzione (questa può essere una funzione anonima).

Infine, controllare sempre che la parola chiave this punti a ciò che si pensa che punti (vedere http://www.alistapart.com/articles/getoutbindingsituations).

Rivolgendosi Domanda 2:

Credo che per le normali funzioni, this è impostato al window oggetti indipendentemente da dove sono dichiarate. Quindi spostare il codice in una funzione separata non risolverebbe il problema.

+1

Non introdurrebbe una perdita di memoria? – tsilb

+1

@shrimpy: È un problema complesso, ma questo articolo lo descrive abbastanza bene: http://www.alistapart.com/articles/getoutbindingsituations. Fondamentalmente, "questo" non punta alla classe Message all'interno della funzione anonima. Per risolvere questo problema, creiamo una variabile (l'ho chiamata "_questo"), facciamo in modo che punti alla classe Message corretta, e quindi usiamo questa variabile quando vogliamo fare riferimento alla classe all'interno della funzione anonima. –

+0

@tslib: In che modo? Questa soluzione è abbastanza comune. Se sei preoccupato che la funzione anonima manterrà le cose bloccate, sono abbastanza sicuro che verrà rimosso dal Garbage Collector non appena "setTimeout" avrà finito con esso. –

2

per rispondere alla tua ultima domanda: "Perché doesn` t funziona se lo facciamo":

Message = function() { 

... 
...   

this.messageFactory = ... 
this.feedbackTag = document.getElementById('feedbackMessages'); 
// public function 
this.addInfo = function (message) { 
    var info = this.messageFactory.createInfo(message); // create a div 
    this.feedbackTag.appendChild(info); 

    delayRemove(info); 

}; 
// private function 
function delayRemove(obj) { 
    var _this = this; 
    setTimeout(function() { _this.feedbackTag.removeChild(info); }, 5000); 
}} 

Non funziona perché si sta passando una variabile non definita (info) al posto di una variabile definita (obj). Ecco la funzione di correzione:

function delayRemove(obj) { 
var _this = this; 
setTimeout(function() { _this.feedbackTag.removeChild(obj); }, 5000);} 
9

Un modo più ordinato è passare solo questo come argomento per la funzione chiamata in timeout:

function delayRemove(obj) { 
    setTimeout(function(_this) { 
     _this.feedbackTag.removeChild(obj); 
    }, 5000, this); 
} 

Si dovrebbe passare obj come un argomento pure, giusto per assicurarsi che sia in ambito (il numero di parametri è illimitato):

function delayRemove(obj) { 
    setTimeout(function(_this, removeObj) { 
     _this.feedbackTag.removeChild(removeObj); 
    }, 5000, this, obj); 
} 

HTML5 e Node.js hanno esteso la funzione setTimeout per accettare i parametri passati alla funzione di richiamata. Ha la seguente firma del metodo.

setTimeout(callback, delay, [param1, param2, ...])

Come setTimeoutisn't actually a JavaScript feature i risultati possono variare tutti i browser. Non sono riuscito a trovare dettagli concreti di supporto, tuttavia, come ho detto, questo è nelle specifiche HTML5.

+1

tutti i browser ora supportano il terzo parametro di setTimeout? – StefanoCudini

+0

@StefanoCudini Risposta aggiornata. –

Problemi correlati