web-dev-qa-db-fra.com

setTimeout () dans la classe JavaScript en utilisant "this"

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

}

33
Dean

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

62
Tikhon Jelvis

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)));
    }
}
5
GordonM
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').

3
Gijs

this est sensible au contexte dans lequel elle est appelée. Lorsque vous passez une chaîne à setTimeout, il s'agit alors de evaled 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))
              );
}
2
Quentin

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

Notez que la transmission de paramètres supplémentaires à la fonction dans la première syntaxe ne fonctionne pas dans Internet Explorer.

2
nandin

As-tu essayé;

window.setTimeout("myObject.run" ,(1000 * randomNumber(1,5)));
1
BusterLuke

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
0
Vitim.us

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/

0
philn5d

Chemin plus court. Sans fonction anonyme.

    var self = this;
    setTimeout(self.method, 1000);
0
Ngorco

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/

0
KalEl