2009-02-26 14 views
24

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, recibo un error que dice method2 no está definido. ¿Qué estoy haciendo mal aquí?setTimeout y "this" en JavaScript

ejemplo:

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]; 
     } 
    } 
}; 
+0

Sólo para asegurarse: es "finction" justo un error tipográfico en la pregunta o también está en tu código? –

+0

Agregue la definición y el alcance del método2 –

+0

Lo sentimos, es un error tipográfico –

Respuesta

38

El problema es que setTimeout() hace que javascript use el alcance global. Básicamente, llama a la clase method(), pero no a this. En cambio, solo está diciendo setTimeout para usar la función method, sin un alcance particular.

Para arreglar esto puede envolver la llamada de 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 haber this porque es callMethod() 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á leer en closures.

Además, como nota al margen, se está preparando para un ciclo infinito, ya que method() siempre llama a method().

+0

Esto se ve prometedor. Voy a probarlo y dejarte saber –

+0

¡Oye, esto funciona en mozilla bu no en ie! ¿Cualquier pista? también las imágenes no giran, se detiene una vez que alcanza la última imagen –

+2

eres un mago. – ihatecache

7

la this que utilizó en la determinación del alcance setTimeOut es a través del mismo. Cree un var "foo = this;" dentro de su función t est.prototype.method y use foo en su lugar.

0

consigo un error que dice metodo2 no está definido

Sí, cuando se mire fuera this.method de su dueño y pasa a la función solo para setTimeout, se pierde la asociación que establece this, por lo this en method() es igual al objeto global window.

Consulte this answer para obtener una explicación de la sorprendente manera en que this funciona en realidad en JavaScript.

39

Una opción más elegante es agregar .bind(this) al final de su función. Por ejemplo:

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

Así que la respuesta a la pregunta del OP podrían 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 
    }; 
+0

círculo obtiene el cuadrado! –

0

en ES6 puede hacerlo de esta manera

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