40 votes

setTimeout et "this" en JavaScript

J'ai une méthode qui utilise le setTimeout et fait un appel à une autre méthode. Au chargement initial, la méthode 2 fonctionne bien. Cependant, après le délai d'attente, j'obtiens une erreur qui dit method2 est indéfini. Qu'est-ce que je fais de mal ici ?

ex :

test.prototype.method = function()
{
    //method2 returns image based on the id passed
    this.method2('useSomeElement').src = "http://www.some.url";
    timeDelay = window.setTimeout(this.method, 5000);
};

test.prototype.method2 = function(name) {
    for (var i = 0; i < document.images.length; i++) {
        if (document.images[i].id.indexOf(name) > 1) {
            return document.images[i];
        }
    }
};

58voto

Warren Points 355

Une option plus élégante consiste à ajouter .bind(this) à la fin de votre fonction. Par exemple :

    setTimeout(function() {
        this.foo();
    }.bind(this), 1000);
//   ^^^^^^^^^^^ <- fix context

La réponse à la question de l'OP pourrait donc être :

    test.prototype.method = function()
    {
        //method2 returns image based on the id passed
        this.method2('useSomeElement').src = "http://www.some.url";
        timeDelay = window.setTimeout(this.method.bind(this), 5000);
        //                                       ^^^^^^^^^^^ <- fix context
    };

49voto

Daniel Lew Points 39063

Le problème est que setTimeout() fait en sorte que le javascript utilise la portée globale. Essentiellement, vous appelez le method() mais pas de la classe this . Au lieu de cela, vous dites juste setTimeout pour utiliser la fonction method sans portée particulière.

Pour résoudre ce problème, vous pouvez envelopper l'appel de fonction dans un autre appel de fonction qui fait référence aux variables correctes. Cela ressemblera à quelque chose comme ceci :

test.protoype.method = function()
{
    var that = this;

    //method2 returns image based on the id passed
    this.method2('useSomeElement').src = "http://www.some.url";

    var callMethod = function()
    {
        that.method();
    }

    timeDelay = window.setTimeout(callMethod, 5000);
};

that peut être this porque callMethod() est dans le champ d'application de la méthode.

Ce problème devient plus complexe lorsque vous devez passer des paramètres à la fonction setTimeout car IE ne prend pas en charge plus de deux paramètres à la méthode setTimeout . Dans ce cas, vous devrez lire les documents suivants fermetures .

En outre, vous vous préparez à une boucle infinie, puisque method() appelle toujours method() .

8voto

Jason Points 546

Le site this que vous avez utilisé dans setTimeout est le scoping par lui-même. Créez un var _this = this; à l'intérieur de votre test.prototype.method fonction et utilisation _this à la place.

5voto

user889030 Points 909

Dans es6 vous pouvez le faire comme ceci

window.setTimeout(() => {
    this.foo();
}, 1000);

1voto

bobince Points 270740

J'obtiens une erreur qui dit que la méthode 2 est indéfinie.

Oui, quand vous coupez this.method de son propriétaire et passe la fonction seule à setTimeout vous perdez l'association qui définit this donc this en method() est égal à l'objet global window .

Voir cette réponse pour une explication de la manière surprenante this fonctionne en fait en JavaScript.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X