2009-11-22 3 views
4

Lorsque vous cliquez sur chaque div, elle doit alerter '1' si vous avez cliqué sur div 1 ou '5' si vous avez cliqué sur div 2. J'ai essayé de rendre ce code aussi facile que possible parce que cela est nécessaire dans une application beaucoup plus grande.Portée variable Javascript dans la fonction anonymous addEventListener

<html> 
<head> 
<style type="text/css"> 
#div1 { background-color: #00ff00; margin: 10px; padding: 10px; } 
#div2 { background-color: #0000ff; margin: 10px; padding: 10px; } 
</style> 
<script type="text/javascript"> 

function init() 
{ 
    var total = 1; 

    var div1 = document.getElementById('div1'), 
     div2 = document.getElementById('div2'); 

    var helper = function(event, id) 
    { 
     if (event.stopPropagation) event.stopPropagation(); 
     if (event.preventDefault) event.preventDefault(); 

     alert('id='+id); 
    } 

    div1.addEventListener('click', function(event) { helper(event, total); }, false); 

    total += 4; 

    div2.addEventListener('click', function(event) { helper(event, total); }, false); 

} 

</script> 
</head> 

<body onload="init();"> 

<div id="div1">1</div> 
<div id="div2">2</div> 

</body> 
</html> 

Nous vous remercions de votre aide! :-)

Répondre

8

Le problème est que les auditeurs de l'événement et « total » les deux existent dans le même champ (init())

Les fonctions d'événements vont toujours faire référence au total dans le cadre init(), même si elle est modifiée après la déclaration des fonctions d'événement

Pour contourner ce problème, les fonctions d'événement doivent avoir un 'total' dans leur propre étendue qui ne changera pas. Vous pouvez ajouter une autre couche de champ en utilisant une fonction anonyme

Par exemple:

(function (total) { 
    div1.addEventListener('click', function(event) { helper(event, total); }, false); 
}(total)); 

total += 4; 

(function (total) { 
    div2.addEventListener('click', function(event) { helper(event, total); }, false); 
}(total)); 

Les fonctions anonymes sont transmises valeur totale « 'actuelle d » init() en tant que paramètre. Ceci définit un autre 'total' à la portée de la fonction anonyme, donc cela n'a pas d'importance si le total de init() change ou non, car la fonction d'événement référencera FIRST la portée de la fonction anonyme.

Edit:

, vous devez également placer un point-virgule après l'accolade de fermeture de la fonction d'aide, sinon le script se plaindra que « événement » est indéfini.

var helper = function(event, id) 
{ 
    if (event.stopPropagation) event.stopPropagation(); 
    if (event.preventDefault) event.preventDefault(); 

    alert('id='+id); 
}; 
+0

Ahh. Donc, le total devient comme un pointeur variable, un peu comme dans la variable C++ *? –

+0

En fait, il est copié dans une portée locale. S'il s'agissait d'un pointeur, il changerait à la fois à l'intérieur et à l'extérieur de la portée, ce qui vous ramènerait à votre problème d'origine. – Matt

+2

L'exemple de @Gary Matt est correct, voici une petite terminologie pour vous. Vous étiez confronté à votre problème spécifique à cause de quelque chose de connu sous le nom de "fermeture" (http://www.jibbering.com/faq/faq_notes/closures.html), qui est une fonctionnalité géniale et puissante de JavaScript. Ce que Matt vous a montré, c'est comment contourner la propriété de fermeture (qui parfois se met en travers comme vous l'avez vu) en utilisant des fonctions anonymes et une technique connue sous le nom de currying. Voir http://ejohn.org/blog/partial-functions-in-javascript/ et http://stackoverflow.com/questions/1413916/. –

2

Ceci est à peu près la même chose, mais je pense que ce sera mieux:

div1.addEventListener('click', function(t){ return function(event) { helper(event, t); }}(total), false); 

au lieu de:

(function (total) { 
    div2.addEventListener('click', function(event) { helper(event, total); }, false); 
}(total)); 
Questions connexes