whatwg - setTimeout y "this" en JavaScript
whatwg español (5)
Me sale un error que dice que method2 no está definido
Sí, cuando this.method
de su propietario y pasas la función solo a setTimeout
, pierdes la asociación que establece this
, por lo que this
en method()
es igual a la window
objeto global.
Consulte esta respuesta para obtener una explicación de la sorprendente manera en que this
realmente funciona en JavaScript.
Tengo un método que usa la función setTimeout
y realiza una llamada a otro método. En el método de carga inicial 2 funciona bien. Sin embargo, después del tiempo de espera, aparece un error que dice que el method2
no está definido. ¿Qué estoy haciendo mal aquí?
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];
}
}
};
El problema es que setTimeout()
hace que javascript use el alcance global. Básicamente, estás llamando a la clase method()
, pero no a partir de this
. En su lugar, solo le está diciendo a setTimeout
que use el method
función, sin un alcance particular.
Para solucionarlo, puede ajustar la llamada a la función en otra llamada de función que haga referencia a las variables correctas. Se verá algo como esto:
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
puede ser porque callMethod()
encuentra dentro del alcance del método.
Este problema se vuelve más complejo cuando necesita pasar parámetros al método setTimeout
, ya que IE no admite más de dos parámetros para setTimeout
. En ese caso, deberás leer sobre closures .
Además, como nota al margen, te estás preparando para un ciclo infinito, ya que el method()
siempre llama a method()
.
Una opción más elegante es agregar .bind(this)
al final de su función. P.ej:
setTimeout(function() {
this.foo();
}.bind(this), 1000);
// ^^^^^^^^^^^ <- fix context
Entonces, la respuesta a la pregunta del OP podría 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
};
el this
que setTimeOut
en setTimeOut
está setTimeOut
por sí mismo. Crea una var "foo = this;"
dentro de su función t est.prototype.method
y use foo
lugar.
en es6 puedes hacerlo así
window.setTimeout(() => {
this.foo();
}, 1000);