setInterval e setTimeout
A função setTimeout do javascript difere-se da setInterval por um detalhe: setInterval executa a função passada por parâmetro infinitamente em intervalos de milisegundos passados como segundo parâmetro à função. Ex: setInterval('funcao()', 1000).
Obs: 1000 milisegundos equivalem à 1 segundo.
A função setTimeout executa a função passada por parâmetro apenas uma vez, depois de passados a espera, também em milisegundos, ao segundo parâmetro da função. Ex: setTimeout('funcao()', 1000)
Como passar métodos por parâmetro
É possível programar em javascript orientado a objetos. Nesse post não vou entrar nos detalhes de orientação à objetos. Mas se você desejar passar um método por parâmetro dentro de seu objetos para uma das funções acima?
Primeiro, há outra forma de passar a função por parâmetro: (Iremos referenciar sempre setInterval, mas tudo que se aplica à essa, se aplica a setTimeout. A diferença entre as duas está no tópico anterior)
setInterval(funcao, 1000). Ou seja, passa uma função apenas pelo nome, nesse caso é passado a referência da função.
Dado a seguinte classe:
Esse código funciona?
Funciona!
MAS
Se quiséssemos chamar um outro método dentro do Classe.metodo e ainda passar parâmetros para o método passado na função, NÃO FUNCIONA!
Mudando a classe anterior:
Primeiro, esse código gerará um erro, você não está passando uma referência da função para setInterval e sim o valor resultante da função, nesse caso undefined. Esse problema é fácil de resolver:
Ótimo, agora estou passando a referência de uma função que executa o método em seu corpo. Mas ainda causará um erro. A função this.metodo2() não está definida!
Isso acontece porquê o this.metodo está sendo chamado repetidamente dentro do contexto do objeto window, ao qual pertence a função setInterval e setTimeout (window.setInterval, window.setTimeout) e não dentro do contexto do objeto. Dessa forma, os métodos chamados dentro do método passado por parâmetro estarão dentro do contexto de window.
A SOLUÇÃO
Devemos passar uma cópia do objeto para a função chamada em setInterval ou setTimeout dessa forma:
Como passar métodos por parâmetro
É possível programar em javascript orientado a objetos. Nesse post não vou entrar nos detalhes de orientação à objetos. Mas se você desejar passar um método por parâmetro dentro de seu objetos para uma das funções acima?
Primeiro, há outra forma de passar a função por parâmetro: (Iremos referenciar sempre setInterval, mas tudo que se aplica à essa, se aplica a setTimeout. A diferença entre as duas está no tópico anterior)
setInterval(funcao, 1000). Ou seja, passa uma função apenas pelo nome, nesse caso é passado a referência da função.
Dado a seguinte classe:
<script type="text/javascript"> function Classe() { var intervalo = 1; // Intervalo em segundos this.metodo = function() { alert("Estou dentro de um setInterval!"); } // Aqui vai o método que chama o setInterval e passa o this.metodo como parâmetro this.set = function() { setInterval(this.metodo, intervalo*1000); // Transforma segundos em milisegundos multiplicando por 1000 } } var c = new Classe(); c.set(); </script>
Esse código funciona?
Funciona!
MAS
Se quiséssemos chamar um outro método dentro do Classe.metodo e ainda passar parâmetros para o método passado na função, NÃO FUNCIONA!
Mudando a classe anterior:
<script type="text/javascript"> function Classe() { var intervalo = 1; // Intervalo em segundos this.metodo = function(msg) { this.metodo2(msg); // Chamando um outro método para exibir o alert } this.metodo2 = function(msg) { alert(msg); } // Aqui vai o método que chama o setInterval e passa o this.metodo como parâmetro this.set = function(msg) { setInterval(this.metodo(msg), intervalo*1000); // Transforma segundos em milisegundos multiplicando por 1000 } } var c = new Classe(); c.set('Estou dentro de um setInterval'); </script>
Primeiro, esse código gerará um erro, você não está passando uma referência da função para setInterval e sim o valor resultante da função, nesse caso undefined. Esse problema é fácil de resolver:
setInterval(function() {this.metodo(msg);}, intervalo*1000);
Ótimo, agora estou passando a referência de uma função que executa o método em seu corpo. Mas ainda causará um erro. A função this.metodo2() não está definida!
Isso acontece porquê o this.metodo está sendo chamado repetidamente dentro do contexto do objeto window, ao qual pertence a função setInterval e setTimeout (window.setInterval, window.setTimeout) e não dentro do contexto do objeto. Dessa forma, os métodos chamados dentro do método passado por parâmetro estarão dentro do contexto de window.
A SOLUÇÃO
Devemos passar uma cópia do objeto para a função chamada em setInterval ou setTimeout dessa forma:
<script type="text/javascript"> function Classe() { var self = this; // Essa é a cópia do objeto var intervalo = 1; // Intervalo em segundos this.metodo = function(msg) { this.metodo2(msg); } this.metodo2 = function(msg) { alert(msg); } // Aqui vai o método que chama o setInterval e passa o this.metodo como parâmetro this.set = function(msg) { setInterval(function() {self.metodo(msg);}, intervalo*1000); // E aqui enviamos o método no contexto desse objeto } } var c = new Classe(); c.set('Estou dentro de um setInterval'); </script>
Atente às linhas:
var self = this;
Faz a cópia do objeto para uma variável privada do objeto.
setInterval(function() {self.metodo(msg);}, intervalo*1000);
Aqui é feita a "mágica", passo uma função por referência que executa o método pelo objeto passado por cópia, e não this, que estariam referenciando o objeto window.
Qualquer dúvida, só postar nos comentários. Até a próxima!