2009-07-09 7 views
24

Pourquoi ne puis-je pas utiliser setTimeout dans un objet javascript?Comment utiliser "setTimeout" pour appeler l'objet lui-même

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

    }; 
} 

Merci pour Steve`s Solution, maintenant il ne fonctionnera que si le code est comme ci-dessous ... parce que « ceci » avant a été fait en montrant la fonction au sein setTimeOut, il ne peut pas rearch message.

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

    }; 
} 

Mais pourquoi doesn`t ça marche si nous faisons cela:

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

duplication possible de [Comment accéder à la 'this'/contexte correct dans un rappel?] (Http://stackoverflow.com/q/20279484/1048572) – Bergi

+0

Duplicata: [setTimeout() dans la classe JavaScript en utilisant" this "] (Http://stackoverflow.com/questions/5911211/settimeout-inside-javascript-class-using-this) et [Utilisation de setTimeout() dans une fonction de classe JavaScript] (http://stackoverflow.com/questions/ 6997921/using-settimeout-within-a-javascript-class-function) – handle

Répondre

84

Essayez de remplacer cette ligne:

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

avec ces deux lignes:

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

Note:

Ne passez jamais une chaîne, car elle appelle eval (que vous ne devez utiliser que si nécessaire). Au lieu de cela, passez setTimeout une référence de fonction (cela peut être une fonction anonyme). Enfin, vérifiez toujours que le mot-clé this pointe vers ce que vous pensez qu'il indique (voir http://www.alistapart.com/articles/getoutbindingsituations).

Aborder Question 2:

Je crois que pour les fonctions normales, this est réglé sur l'objet quel que soit window où ils sont déclarés. Donc, déplacer le code dans une fonction séparée ne résoudrait pas le problème.

+1

Cela n'introduirait-il pas une fuite de mémoire? – tsilb

+1

@shrimpy: C'est un problème complexe, mais cet article le décrit assez bien: http://www.alistapart.com/articles/getoutbindingsituations. Fondamentalement, "ceci" ne pointe pas vers la classe Message à l'intérieur de la fonction anonyme. Pour résoudre ce problème, nous créons une variable (je l'ai appelée "_this"), la faisons pointer vers la classe Message correcte, puis utilisons cette variable lorsque nous voulons référencer la classe à l'intérieur de la fonction anonyme. –

+0

@tslib: De quelle façon? Cette solution de contournement est assez courante. Si vous craignez que la fonction anonyme ne reste bloquée, je suis à peu près certain que le garbage collector la zappera dès que "setTimeout" en aura fini avec. –

2

Pour répondre à votre dernière question: « Pourquoi doesn`t fonctionner si nous faisons cela »:

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

Il ne fonctionne pas parce que vous passez une variable non définie (info) au lieu d'une variable définie (obj). Voici la fonction corrigée:

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

Une façon plus propre est de passer juste ce comme argument à la fonction appelée dans le délai d'attente:

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

Vous devriez vraiment passer obj comme un argument aussi, juste pour s'assurer qu'il est dans la portée (le nombre de paramètres est illimité):

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

HTML5 et Node.js ont étendu la fonction setTimeout pour accepter les paramètres transmis à votre fonction de rappel. Il a la signature de méthode suivante.

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

Comme setTimeoutisn't actually a JavaScript feature vos résultats peuvent varier selon les navigateurs. Je n'ai pas trouvé de détails concrets sur le support, cependant, comme je l'ai dit, c'est dans la spécification HTML5.

+1

tous les navigateurs supportent maintenant le troisième paramètre de setTimeout? – StefanoCudini

+0

@StefanoCudini Réponse mise à jour. –