J'essaie d'utiliser setTimeout()
dans une fonction de classe en JavaScript. setTimeout()
est censé déclencher une autre méthode dans la même classe. La fonction que je transmets est donc écrite sous la forme window.setTimeout("this.anotherMethod", 4000)
. Cela pose le problème: this
fait référence à l’objet appelant, dans le cas de setTimeout()
, il s’agit de window
. Comment utiliser des pièces jointes pour renvoyer une référence à l'objet de classe lui-même?
myObject = function(){
this.move = function(){
alert(this + " is running");
}
this.turn = function(){
alert(this + " is turning");
}
this.wait = function(){
window.setTimeout("this.run" ,(1000 * randomNumber(1,5)));
}
this.run = function(){
switch(randomNumber(0,2)){
case 0:
this.move();
break;
case 1:
this.turn();
break;
case 2:
this.wait();
}
}
}
Tu peux le faire:
var that = this;
setTimeout(function () {
that.doStuff();
}, 4000);
Vous pouvez également bind
pour un code plus succinct (comme initialement souligné par @Raynos):
setTimeout(this.doStuff.bind(this), 4000);
bind
est une fonction de bibliothèque standard pour exactement ce modèle de codage (c'est-à-dire capturer this
lexiquement).
this
peut être problématique en javascript, comme vous l'avez découvert.
Je travaille généralement autour de cela en créant un alias this
dans l'objet afin de pouvoir utiliser l'alias à chaque fois que j'ai besoin d'une référence à l'objet contenant.
MyObject = function ()
{
var self = this;
// The rest of the code goes here
self.wait = function(){
window.setTimeout(self.run ,(1000 * randomNumber(1,5)));
}
}
this.wait = function(){
var self = this;
window.setTimeout(function() { self.run() } ,(1000 * randomNumber(1,5)));
}
Ainsi, vous stockez la référence à l'objet que vous appelez .run dans une variable locale ('self').
this
est sensible au contexte dans lequel elle est appelée. Lorsque vous passez une chaîne à setTimeout
, il s'agit alors de eval
ed dans un contexte complètement différent.
Vous devez conserver la valeur actuelle de this
(en la copiant dans une variable différente) et conserver la portée (en n'utilisant pas (implicitement) eval
).
this.wait = function(){
var self = this;
setTimeout(function () { self.run() },
(1000 * randomNumber(1,5))
);
}
Au sommet de votre myObject
principale, faites une nouvelle référence à la valeur actuelle de this
:
var self = this;
puis créez une fermeture pour votre rappel de minuterie qui utilise cette nouvelle référence au lieu de l'objet global que setTimeout
utilisera comme contexte par défaut dans les rappels:
setTimeout(function() {
self.run();
}, 4000);
var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]);
dans func
, this
toujours faire référence à l'objet global. vous pouvez passer l'objet actuel dans func,
var timeoutID = window.setTimeout(func, delay, this);
function func(that) {...}
malheureusement cela ne marche pas dans IE
As-tu essayé;
window.setTimeout("myObject.run" ,(1000 * randomNumber(1,5)));
Il n'est pas recommandé d'utiliser setTimeout ou setInterval à l'aide de chaînes
setTimeout("myFunction()", 5000);
//this is the same as
setTimeout(function(){ eval("myFunction()"); }, 5000)); //<-- eval == BAD
Couru dans une situation plus complexe ... la classe A a un membre de type B et une méthode qui appelle setTimeout qui appelle une méthode sur la classe B. Résolue comme suit:
class A {
constructor(b) {
this.b = b;
}
setTimer(interval) {
setTimeout(this.b.tick.bind(this.b), interval);
}
}
class B {
constructor(name){
this.name = name;
this.ele = window.document.getElementById('B');
}
tick() {
console.log(this);
this.ele.innerText += ' ' + this.name;
}
}
Ce qui lie A.b à cela au sein de B.tick et qui fonctionne.
Voici un violon avec bind
: https://jsfiddle.net/jrme9hyh/
Et un sans bind
qui échoue: https://jsfiddle.net/2jde8tq3/
Chemin plus court. Sans fonction anonyme.
var self = this;
setTimeout(self.method, 1000);
Vous pouvez utiliser ce code à la place, qui fonctionne dans tous les navigateurs modernes -
setTimeout(function(thisObj) {thisObj.run();},1000,this);
Réf: http://klevo.sk/javascript/javascripts-settimeout-and-how-to-use-it-with-your-methods/