Usando `this` no escopo baseado em setTimeout / setInterval

Frequentemente precisamos definir um setTimeout()ou setInterval()dentro de um escopo especial como uma determinada classe. A função setTimeout()/ setInterval()deve chamar um método privilegiado ou público de uma determinada classe e a thispalavra-chave de acesso a . Muitas vezes as pessoas ainda tentam iniciar um tempo limite / intervalo usando o seguinte e não têm sucesso com isso:

Errado:

function myCounter() {
this.i = 0;

this.init();
}

myCounter
.prototype.init = function() {
setInterval
(this.countUp,500); // fails
setInterval
(function() { this.countUp(); }, 500); // also fails, this is in a different scope
};

myCounter
.prototype.countUp = function() {
this.i++;
document
.getElementById('counter').innerHTML = this.i;
};

O exemplo acima está totalmente correto, exceto para chamar a função dentro do loop. Não é possível usar this.counUp () dentro de outro escopo, não está mais relacionado à classe desejada, assim que é disparado. Portanto, temos que conectar uma variável ao nosso escopo atual, definindo uma nova variável e atribuindo thisa ela. Fe Isso vai funcionar. Mesmo na função chamada, funcionará bem já que estamos no escopo correto de nossa classe. Agora, um exemplo prático:var _this = this; setInterval(function() { _this.countUp(); }, 500);this

Corrigir:

// basic class implementation
function myCounter() {
// privileged property for iteration
this.i = 0;

// privileged init method
this.init();
}

// defining init method
myCounter
.prototype.init = function () {
// reassign this
var _this = this;
setInterval
(function () {
// call this.countUp() using our new created variable.
// this has to be done as this would normally call something
// inside this function, so we have to pass it as own
// variable over
_this
.countUp();
}, 500);
};

// defining the counter method
myCounter
.prototype.countUp = function () {
this.i++;
document
.getElementById('counter').innerHTML = this.i;
};

// create a new instance of our counter class
var counter = new myCounter();

jsFiddle Demo

Correto # 2:

Outro exemplo de trabalho é o uso do método ECMAScript5s, bind(this, [arg1, arg2, arg3])que nos permite vincular argumentos a uma função, no nosso caso, estamos ignorando this. Esta é a maneira mais avançada de fazer isso, mas também tenha em mente que essa função ainda é bastante nova e não é tão amplamente suportada como a primeira maneira de fazer isso. Você pode dar uma olhada na tabela de compatibilidade na parte inferior da seguinte página: tabela de compatibilidade bind () . Tudo o que temos a fazer é atribuir a função desejada dentro do tempo limite / intervalo da seguinte forma, setInterval(this.countUp.bind(this), 500);é isso! Pedaço de bolo, não é? 🙂 Agora, um exemplo prático:

// basic class implementation
function myCounter() {
// privileged property for iteration
this.i = 0;

// privileged init method
this.init();
}

// defining init method
myCounter
.prototype.init = function () {
setInterval
(
// we can also use bind() to assign the correct scope
this.countUp.bind(this)
, 500);
};

// defining the counter method
myCounter
.prototype.countUp = function () {
this.i++;
document
.getElementById('counter').innerHTML = this.i;
};

// create a new instance of our counter class
var counter = new myCounter();

jsFiddle Demo