2010-02-25 13 views
10

Tengo un problema con la creación de un objeto Javascript y los métodos de llamada dentro de ese objeto utilizando setTimeout. He intentado varias soluciones, pero siempre durante la segunda parte de mi ciclo el alcance se convierte en el objeto ventana en lugar de en mi objeto personalizado. Advertencia: soy bastante nuevo en javascript.Métodos de llamada a objetos personalizados con setTimeout pierde alcance

mi código:

$(function() { 
slide1 = Object.create(slideItem); 
slide1.setDivs($('#SpotSlideArea')); 
slide1.loc = 'getSpot'; 
slide2 = Object.create(slideItem); 
slide2.setDivs($('#ProgSlideArea')); 
slide2.loc = 'getProg'; 
slide2.slide = 1; 
setTimeout('triggerSlide(slide1)', slide1.wait); 
setTimeout('triggerSlide(slide2)', slide2.wait); 
}); 

function triggerSlide(slideObject) { 
slideObject.changeSlide(slideObject); 
} 

var slideItem = { 
div1: null, 
div2: null, 
slide: 0, 
wait: 15000, 
time: 1500, 
loc: null, 
changeSlide: function(self) { 
    this.slide ? curDiv = this.div1:curDiv = this.div2; 
    $(curDiv).load(location.pathname + "/" + this.loc, this.slideGo(self)); 
}, 
setDivs: function(div) { 
    var subDivs = $(div).children(); 
    this.div1 = subDivs[0]; 
    this.div2 = subDivs[1]; 
}, 
slideGo: function(self) { 
    if(this.slide) { 
    $(this.div2).animate({ 
    marginLeft: "-300px" 
    }, this.time); 
    $(this.div1).animate({ 
    marginLeft: "0" 
    }, this.time); 
    setTimeout('triggerSlide(self)', this.wait); 
    } else {  
    $(this.div1).animate({ 
    marginLeft: "300px" 
    }, this.time); 
    $(this.div2).animate({ 
    marginLeft: "0" 
    }, this.time); 
    setTimeout('triggerSlide(self)', this.wait); 
    } 
    this.slide ? this.slide=0:this.slide=1; 
} 
} 

Mi último intento fue la construcción de la triggerSlide función auxiliar para que pudiera intentar pasar la referencia al objeto a través de mis métodos, pero incluso eso no parece funcionar.

que podría utilizar setInterval y funciona, sin embargo:

  1. que quieren asegurarse de que la animación se ha completado antes de que el temporizador se reinicia
  2. no aprendo cómo llegar en torno al tema de esa manera. :)

Respuesta

15

Esto debería ser una lectura obligatoria para los programadores de Javascript que comienzan con el lenguaje (y con Stackoverflow).

A diferencia de Java, no existe un "enlace" intrínseco de funciones con ningún objeto, independientemente de cómo se declaren. La vinculación del contexto del objeto ocurre solo en el tiempo de invocación de la función. Por lo tanto, cuando pasas una referencia a una función a algo así como "setTimeout", no importa en absoluto que obtengas la función de algún objeto. Es solo una función, y "setTimeout" lo llamará con el contexto predeterminado — el objeto window.

Hay muchas maneras de manejar esto (y no lo llamaré un "problema", es un hecho del lenguaje, y uno muy poderoso). Si estuvieras usando un framework de algún tipo, sería más fácil.

Otra cosa: está vinculando los manejadores de tiempo de espera y de intervalo como cadenas que contienen código. Esa es una práctica bastante fea, por lo que debe acostumbrarse a formar expresiones de función —, es decir, expresiones cuyos valores son funciones.

su carretilla para "slideItem", por ejemplo, es posible hacer esto:

// ... 
setTimeout(function() { slideItem.changeSlide(); }, 5000); 

De esta manera, la función llamada por el mecanismo de tiempo de espera siempre invocar "changeSlide" con su objeto "slideItem" como el contexto. No necesita ese parámetro "self" en "changeSlide" porque "this" apuntará al objeto correcto.

[edit] Observo que de hecho está haciendo un cierto uso de jQuery, que es una buena cosa.

+0

Por lo general, es mejor evitar el código +1 en cadenas a menos que sea absolutamente necesario. Eso incluye 'new Function ('algún código');', 'setTimeout (" doSomething() ", 0);' y el favorito de todos, 'eval ('some code');'. Los dos primeros de los cuales * nunca * he visto una necesidad, el tercero solo para JSON y las expresiones matemáticas de entrada :-) –

+0

He intentado lo anterior, y funciona para la llamada inicial, pero las llamadas para repetir la acción (las llamadas a setTimeout() en slideGo() todavía no funcionan. Las formateé como las anteriores, pero utilicé esto en lugar de slideItem anterior, es decir, setTimeout (function() {this.changeSlide();}, this.wait); Aparece un error en Firebug de que this.changeSlide() no es una función. Sé desde el principio del método slideGo que 'this' hace referencia a mi slideItem, sin embargo, no aparece cuando ocurre esa segunda llamada a setTimeout. es donde estoy confundido. –

+0

También debo mencionar que traté de agregar eso = esto al principio de mi método slideGo, sin embargo, parece que se agrega en un ámbito global en lugar de solo dentro del método. Tengo varios objetos en el página por lo que hace solo uno de animarlos, activados por cada setTimeout. –

0

No puedo probar este código ahora, pero ¿esto ayuda?

setTimeout(function(){triggerSlide(slide1)}, slide1.wait); 
+0

Ugg. ¿Por qué pasarías eso como una cuerda? – Pointy

+0

¿A diferencia de qué? Especificando un nombre de función? – lance

+0

Sí, especificando un nombre de función o una función anónima. En su ejemplo, funcionaría perfectamente quitar las citas por completo.Sin embargo, su mecanismo es innecesariamente complejo de todos modos, y realmente debe hacerse de manera diferente. – Pointy

0

Esto es jQuery, ¿correcto? Hay un parámetro de devolución de llamada a animate(); pase la función que desea que se llame después de que se complete la animación y jQuery se encargará de llamarlo. La devolución de llamada debe capturar el alcance que desea perfectamente.

Cuestiones relacionadas