setTimeout e “this” em JavaScript

Eu tenho um método que usa a function setTimeout e faz uma chamada para outro método. No método de carga inicial 2 funciona bem. No entanto, após o tempo limite, recebo um erro que diz que method2 é indefinido. O que estou fazendo de errado aqui?

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  1) { return document.images[i]; } } }; 

O problema é que setTimeout() faz com que o javascript use o escopo global. Essencialmente, você está chamando a class method() , mas não a partir this . Em vez disso, você está apenas dizendo setTimeout para usar o method function, sem escopo específico.

Para corrigir isso, você pode envolver a chamada de function em outra chamada de function que faça referência às variables ​​corretas. Vai parecer algo assim:

 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 pode ser this porque callMethod() está dentro do escopo do método.

Esse problema se torna mais complexo quando você precisa passar parâmetros para o método setTimeout , já que o IE não suporta mais de dois parâmetros para setTimeout . Nesse caso, você precisará ler os encerramentos .

Além disso, como um sidenote, você está se preparando para um loop infinito, já que method() sempre chama method() .

Uma opção mais elegante é acrescentar .bind(this) ao final de sua function. Por exemplo:

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

Então a resposta para a pergunta do OP poderia ser:

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

o que você usou em setTimeOut é escopo por si só. Crie um var "foo = this;" dentro de sua function t est.prototype.method e use foo .

Eu recebo um erro que diz que method2 é indefinido

Sim, quando você corta this.method de seu dono e passa a function sozinha para setTimeout , você perde a associação que configura this , então this in method() é igual à window object global.

Veja esta resposta para uma explicação da maneira surpreendente como this realmente funciona em JavaScript.

em es6 você pode fazer assim

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