2010-04-22 6 views
0

J'ai un petit problème: slideHelpers.total = 4JS portée des variables missunderstanding

for (i=1;i <= slideHelpers.total; i++) { 
    $('<a href="#">' + i + '</a>').bind('click', function(){ alert('go to the ' + i + ' slide')}).appendTo('.slideaccess') 
} 

l'alerte donne sur 5 ce qui est logique, parce que quand le clic de la fonction déclenche i est en fait 5. Mais je voudrais avoir la même chose que dans mon tag <a>. Quelle est la meilleure façon de gérer cela?

Je pourrais mettre i dans le data() de l'étiquette <a> par exemple mais je suis sûr qu'il y a un moyen plus facile.

+1

Bienvenue à la question de la boucle de fermeture d'aujourd'hui! Voir par exemple. http://stackoverflow.com/questions/2568966/how-do-i-pass-the-value-not-the-reference-of-a-js-variable-to-a-function and many more for background. – bobince

Répondre

2
for (i=1;i <= slideHelpers.total; i++) { 
    $('<a href="#">' + i + '</a>').bind('click', 
     (function(i){ 
      // Capture i in closure 
      return function(){ 
       alert('go to the ' + i + ' slide') 
      }; 
     })(i) 
    ).appendTo('.slideaccess') 
} 

optimisé:

var ary = [], i = 0, n = slideHelpers.total, 
    open = '<a class="index" href="#">', 
    close = '</a>'; 

// Fill array with numbers: 1,2,3,4,5... 
while (++i < n) ary[i] = i + 1; 

$('.slideaccess').append(
    open + ary.join(close + open) + close 
).delegate('a.index', 'click', function() { 
    var index = $.text(this); 
    alert('go to the ' + index + ' slide'); 
}); 
+0

remercie ses travaux, pourriez-vous expliquer votre exemple? – meo

+1

'(function() {...})()' agit comme un wrapper lexical (ou "scope") qui reçoit la valeur ** current ** de 'i' comme argument. La fonction interne (retournée) est techniquement une fermeture, et peut voir le 'i 'capturé. – James

0

Vous pouvez utiliser le eventData de la fonction de liaison:

for (var i = 1; i <= slideHelpers.total; i++) { 
    $('<a href="#">' + i + '</a>').bind('click', { index: i }, function(arg) { 
     alert('go to the ' + arg.data.index + ' slide'); 
    }).appendTo('.slideaccess'); 
} 
+0

comme je l'ai dit dans ma question, je suis à la recherche d'une solution sans avoir à utiliser des données(). – meo

2

Vous pouvez utiliser une fonction supplémentaire qui retourne votre fonction:

for (i=1;i <= slideHelpers.total; i++) { 
    $('<a href="#">' + i + '</a>').bind('click', 
     (function(i) { 
      return function() { 
       alert('go to the ' + i + ' slide'); 
      }; 
     })(i) 
    ).appendTo('.slideaccess'); 
} 

Avec cette fonction supplémentaire, le i intérieur de votre alert fait référence à l'argument i de cette fonction et non au i de l'étendue externe.

1

Vous devez créer une nouvelle étendue, sinon chaque fonction référencera la même i. En JavaScript, les variables sont limitées aux fonctions.

var make_alert_message = function make_alert_message(num) { 
    return function() { 
     alert('go to the ' + num + ' slide'); 
    }; 
} 

for (var i = 1; i <= slideHelpers.total; i++) { 
    $('<a href="#">' + i + '</a>').bind(
     'click', make_alert_message(i) 
     ).appendTo('.slideaccess') 
} 
1

Dans votre exemple de code i est fondamentalement une variable globale. Au moment où le code alert() s'exécute, i a la valeur maximale de la boucle for. La façon standard de résoudre ce problème en JavaScript est de créer une nouvelle fonction qui a son propre scope pour "maintenir" la variable. Prenez par exemple ce code qui renvoie votre fonction de gestion des événements:

(function(i) { // using i as an argument here 'scopes' it 
    var something = i; // also within this function scope. 
    // inside here, both i and something will only ever reference the "local scope" 

    return function() { 
    alert(i); 
    }; 
})(i); // and here we are calling that function with i = 1,2,3,...