2009-07-09 4 views
24

Warum kann ich setTimeout in einem Javascript-Objekt nicht verwenden?Wie "setTimeout" verwenden, um Objekt selbst aufzurufen

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 ?????? 

    }; 
} 

Dank für Steve`s Lösung arbeiten wird es nun, wenn der Code wie unten ist ... , weil die ‚this‘, bevor sie tatsächlich wurde auf die Funktion innerhalb setTimeOut zeigt, ist es nicht rearch Nachricht kann.

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); 

    }; 
} 

Aber warum doesn `t es, wenn wir dies tun:

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

möglich Duplikat von [Wie der richtige 'this/context innerhalb eines Callbacks zugreifen?] (Http://stackoverflow.com/q/20279484/1048572) – Bergi

+0

Duplikate: [setTimeout() innerhalb JavaScript-Klasse mit" this "] (Http://stackoverflow.com/questions/5911211/settimeout-inside-javascript-class-using-this) und [Verwenden von setTimeout() innerhalb einer JavaScript-Klassenfunktion] (http://stackoverflow.com/questions/ 6997921/using-settimeout-innerhalb-einer-javascript-class-function) – handle

Antwort

84

Versuchen Sie, diese Linie zu ersetzen:

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

mit diesen beiden Linien:

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

Hinweis:

Übergeben Sie niemals setTimeout eine Zeichenfolge, da dies eval aufruft (die Sie nur bei Bedarf verwenden sollten). Übergeben Sie setTimeout stattdessen eine Funktionsreferenz (das kann eine anonyme Funktion sein).

Überprüfen Sie abschließend immer, ob das Schlüsselwort this auf das verweist, auf das es sich bezieht (siehe http://www.alistapart.com/articles/getoutbindingsituations).

Frage Adressierung 2:

Ich glaube, dass für den normalen Funktionen, this auf das gesetzt window objekt unabhängig davon, wo sie deklariert sind. Das Verschieben des Codes in eine separate Funktion würde das Problem nicht beheben.

+1

Wäre das nicht ein Speicherleck? – tsilb

+1

@shrimpy: Es ist ein komplexes Problem, aber dieser Artikel beschreibt es ziemlich gut: http://www.alistapart.com/articles/getoutbindingsituations. Im Grunde verweist "this" nicht auf die Message-Klasse innerhalb der anonymen Funktion. Um dieses Problem zu beheben, erstellen wir eine Variable (ich nannte es "_this"), zeigen auf die richtige Message-Klasse und verwenden diese Variable dann, wenn wir auf die Klasse innerhalb der anonymen Funktion verweisen wollen. –

+0

@tslib: In welcher Weise? Diese Problemumgehung ist ziemlich häufig. Wenn Sie sich Sorgen machen, dass die anonyme Funktion die Dinge zusammenhält, bin ich mir ziemlich sicher, dass sie vom Garbage Collector gecastet wird, sobald "setTimeout" damit fertig ist. –

2

Ihre letzte Frage zu beantworten: „Warum doesn` t es, wenn wir dies tun“:

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); 
}} 

Es funktioniert nicht, weil Sie eine undefinierte Variable (info) anstelle eines definierten Variablen sind vorbei (obj). Hier ist die korrigierte Funktion:

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

Eine ordentliche Art und Weise ist nur passiert diese als Argument für die Funktion in der Timeout aufgerufen wird:

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

Sie wirklich obj passieren sollen auch ein Argument, nur um sicherzustellen, dass es in den Geltungsbereich (die Anzahl der Parameter ist unbegrenzt):


HTML5 und Node.js erweiterten die setTimeout-Funktion, um Parameter zu akzeptieren, die an Ihre Rückruffunktion übergeben werden. Es hat die folgende Methodensignatur.

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

Als setTimeoutisn't actually a JavaScript feature Ergebnisse in allen Browsern variieren. Konkrete Details der Unterstützung konnte ich nicht finden, jedoch wie gesagt in der HTML5-Spezifikation.

+1

alle Browser unterstützen jetzt den dritten Parameter von setTimeout? – StefanoCudini

+0

@StefanoCudini Antwort aktualisiert. –