16

El objetivo¿Cómo pasar una variable por valor a una función anónima de JavaScript?

quiero asignar dinámicamente controladores de eventos a algunos divs en las páginas a través de un sitio.

mi método

Im usando jQuery para unirse funciones anónimas como manejadores de eventos div seleccionados.

El problema

El código itera una matriz de nombres DIV y URL asociadas. El nombre div se utiliza para establecer el destino obligatorio, es decir, adjuntar este controlador de eventos a este evento div.

Mientras que los controladores de eventos se unen con éxito a cada uno de los eventos div, las acciones activadas por esos controladores de eventos solo se dirigen al último elemento de la matriz.

Así que la idea es que si el usuario pasa sobre un div dado, debería ejecutar una animación deslizable para ese div. Pero, en cambio, al pasar el mouse sobre div1 (rangeTabAll) se activa una animación deslizable para div4 (rangeTabThm). Lo mismo es cierto para divs 2, 3, etc. El orden no es importante. Cambie los elementos de la matriz y los eventos siempre apuntarán al último elemento de la matriz, div4.

Mi Código - (utiliza jQuery)

var curTab, curDiv; 
var inlineRangeNavUrls=[['rangeTabAll','range_all.html'],['rangeTabRem','range_remedial.html'], 
       ['rangeTabGym','range_gym.html'],['rangeTabThm','range_thermal.html']]; 
     for (var i=0;i<inlineRangeNavUrls.length;i++) 
     { 
      curTab=(inlineRangeNavUrls[i][0]).toString(); 
      curDiv='#' + curTab; 
      if ($(curDiv).length) 
      { 
       $(curDiv).bind("mouseover", function(){showHideRangeSlidingTabs(curTab, true);}); 
       $(curDiv).bind("mouseout", function(){showHideRangeSlidingTabs(curTab, false);}); 
      } 
     } 

mi teoría

estoy bien no ver un error de sintaxis o salta a la vista es un problema pase por referencia. Inicialmente tuve la siguiente instrucción para establecer el valor de curTab:

curTab=inlineRangeNavUrls[i][0]; 

Así que cuando ocurrió el problema que me imaginé que, como he cambiado (a través de iteración del bucle) la referencia a curTab, yo estaba en el hecho de cambiar la referencia para todos los manejadores de eventos de función anónima previos al nuevo valor de curTab también ... y es por eso que los manejadores de eventos siempre se enfocaron en el último div.

Así que lo que realmente tenía que hacer era pasar el valor curTab a los controladores de eventos función anónima no es el objeto curTab referencia.

así que pensé:

curTab=(inlineRangeNavUrls[i][0]).toString(); 

podría solucionar el problema, pero no es así. El mismo trato. Así que claramente me falta algo de conocimiento clave, y probablemente muy básico, sobre el problema. Gracias.

+0

JavaScript siempre pasa y lo asigna por valor. Su pregunta no se trata de aprobar en absoluto; sino más bien con la captura de variables por cierres. – newacct

Respuesta

20

Es necesario crear una nueva variable en cada paso a través del bucle, por lo que obtendrá capturado en los cierres que está creando para los controladores de eventos.

Sin embargo, simplemente mover la declaración de variable en el bucle no lo logrará, porque JavaScript doesn't introduce a new scope for arbitrary blocks.

Una forma fácil de forzar la introducción de un nuevo ámbito de aplicación es utilizar otra función anónima:

for (var i=0;i<inlineRangeNavUrls.length;i++) 
{ 
    curDiv='#' + inlineRangeNavUrls[i][1]; 
    if ($(curDiv).length) 
    { 
    (function(curTab) 
    { 
     $(curDiv).bind("mouseover", function(){showHideRangeSlidingTabs(curTab, true);}); 
     $(curDiv).bind("mouseout", function(){showHideRangeSlidingTabs(curTab, false);}); 
    })(inlineRangeNavUrls[i][0]); // pass as argument to anonymous function - this will introduce a new scope 
    } 
} 

As Jason suggests, en realidad se puede limpiar esto un poco el uso de jQuery integrado hover() función:

for (var i=0;i<inlineRangeNavUrls.length;i++) 
{ 
    (function(curTab) // introduce a new scope 
    { 
    $('#' + inlineRangeNavUrls[i][1]) 
    .hover(
     function(){showHideRangeSlidingTabs(curTab, true);}, 
     function(){showHideRangeSlidingTabs(curTab, false);} 
    ); 
    // establish per-loop variable by passsing as argument to anonymous function 
    })(inlineRangeNavUrls[i][0]); 
} 
+0

Cosas geniales, gracias. – rism

1

Creo que estás haciendo esto más complicado de lo necesario. Si todo lo que hace es asignar un efecto deslizante sobre el mouseover/out, pruebe el efecto hover con jquery.

$("#mytab").hover(function(){ 
    $(this).next("div").slideDown("fast");}, 
    function(){ 
    $(this).next("div").slideUp("fast"); 
}); 

Si usted envió su HTML completo que podía decir exactamente cómo hacerlo :)

+2

cierto, pero eso no es lo que está causando el problema. –

+0

... ¿así que obtengo un voto a favor? para proporcionar una respuesta más simple y clara al problema del OP? ¿De Verdad? – Jason

+0

Su respuesta no resuelve el problema del OP. – Breton

15

lo que está sucediendo aquí es que sus funciones anónimas están formando un cierre y llevando su alcance exterior con ellas. Eso significa que cuando se hace referencia a curTab dentro de su función anónima, cuando el controlador de eventos ejecuta esa función, buscará el valor actual de curTab en su ámbito externo. Eso será lo que le asignaron por última vez a curTab. (No lo fue asignado en el momento que aglutinaba la función)

lo que hay que hacer es cambiar esta situación:

$(curDiv).bind("mouseover", function(){showHideRangeSlidingTabs(curTab, true);}); 

a esto:

$(curDiv).bind("mouseover", 
    (function (mylocalvariable) { 
     return function(){ 
      showHideRangeSlidingTabs(mylocalvariable, true); 
     } 
    })(curTab) 
); 

esto va a copiar el valor de curTab en el alcance de la función externa, que la función interna llevará consigo. Esta copia ocurre al mismo tiempo que vincula la función interna al controlador de eventos, por lo que "mylocalvariable" refleja el valor de curTab en ese momento. Luego, la próxima vez que se recorre el ciclo, se creará una nueva función externa con un nuevo ámbito y se copiará el siguiente valor de curTab.

La respuesta de shog9 logra básicamente lo mismo, pero su código es un poco más austero.

es un poco complicado, pero tiene sentido si lo piensas bien. Los cierres son raros.

editar: oops, se olvidó de devolver la función interna. Fijo.

+0

Gracias un montón, un poco de un lanzamiento de moneda para la respuesta aceptada. – rism

1

Puede poner el valor de su variable en una etiqueta no existente, y luego puede leerlas desde allí. Este fragmento es parte de un cuerpo de bucle:

s = introduction.introductions[page * 6 + i][0]; //The variables content 
$('#intro_img_'+i).attr('tag' , s);    //Store them in a tag named tag 
$('#intro_img_'+i).click(function() {introduction.selectTemplate(this, $(this).attr('tag'));} ); //retrieve the stored data 
+0

para ser compatible con HTML5 puede agregar 'data-' before 'tag' para hacer' data-tag' luego puede usar el método jQuery ['data'] (http://api.jquery.com/data/). – Brombomb

Cuestiones relacionadas