Portées de variables


h1 9/12/2006 03:58:00 AM

Encore un post de geek: devinerez-vous le résultat du petit bout de code suivant?

var bla = ["oof","rab"] ;
var fun = [] ;
for (var i in bla) {
// i varie de 0 à 1
var inside = 2*i ;
fun[i] = function () {
return (inside+"-"+bla[i]) ;
} ;
// (2*3)+"-"+"a" == "6-a"
}
alert("La reponse est: "+fun[0]()+"...") ;

Et le résultat du suivant?

var bla = ["oof","rab"] ;
var fun = [] ;
function fill(i) {
var inside = 2*i ;
fun[i] = function () {
return (inside+"-"+bla[i]) ;
} ;
}
for (var i in bla) { fill(i) }
alert("La reponse est: "+fun[0]()+"...") ;

Lancer le test?

A priori vous vous êtes trompés, et ce n'est pas votre faute mais celle du langage.

L'expérience fonctionne aussi en Python, ça me déçoit de ces deux langages, je pensais que les problèmes de liaison de variables y étaient joliment résolus, comme l'exemple avec une fonction le montre.

Mais qu'est-ce qui se passe, en fait ? Avec une boucle, une seule instance des variables "i" et "inside" est crée, elle persiste d'une étape de l'itération à l'autre. Du coup au moment où on évalue la fonction fun[0], "i" et "inside" ont leur dernière valeur, respectivement 2 et "rab". A la limite pour "i" on dira que c'est spécifié comme cela, mais pour "inside"? La variable est déclarée dans la boucle! Si on veut avoir une variable persistant d'une itération à l'autre, on la déclare hors de la boucle. De même si on veut pouvoir accéder à "i" après la fin de la boucle. Si ce n'est pas l'effet voulu il est naturel de déclarer dans la corps de la boucle, et on voudrait bien que cela change quelquechose!

Edit: la "suite" de cette note est ici.