Dans des cas comme celui ci-dessous, où l’on souhaite créer des éléments et leur attribuer un événement
onclick dépendant d’une variable de boucle :
Code:
1 2 3 4 5 6 7 8
| function foo() {
for (var i = 0; i < 10; i++) {
var MonDiv = document.createElement("div");
MonDiv.textContent = "div " + i;
MonDiv.onclick = function () { alert(i); };
document.body.appendChild(MonDiv);
}
} |
Cette fonction est censée permettre de créer 10 nouveaux divs contenant les textes « div 1 », « div 2 », etc. et de les insérer dans la page. On leur attribue également un
onclick avec pour but de faire un
alert() de « 1 » sur le premier div, « 2 » sur le second, etc.
Malheureusement cela ne fonctionne pas : les divs sont correctement créés et insérés mais au clic, tous affichent le message « 10 ». En fait, la valeur de
i n’est pas évaluée au moment de la mise en place du
onclick, mais seulement au moment où celui-ci est appelé. Or à ce moment, sa valeur vaut bien 10, la dernière valeur de la boucle.
La solution moderne (fin 2017) est d’utiliser le mot-clé
let, apparu avec ECMAScript 2015, qui fonctionne un peu comme
var mais qui limite la portée des variables au bloc courant, en l’occurence le corps de la boucle
for.
Code:
1 2 3 4 5 6 7 8
| function foo() {
for (let i = 0; i < 10; i++) {
let MonDiv = document.createElement("div");
MonDiv.textContent = "div " + i;
MonDiv.onclick = function () { alert(i); };
document.body.appendChild(MonDiv);
}
} |
Si vous développez dans un environnement où
let n’est pas disponible, il faut recourir à une fonction anonyme :
Code:
1 2 3 4 5 6 7 8 9 10 11 12
| function foo() {
for (var i = 0; i < 10; i++) {
var MonDiv = document.createElement("div");
MonDiv.textContent = "div " + i;
(function (arg) {
MonDiv.onclick = function () { alert(arg); };
}(i));
document.body.appendChild(MonDiv);
}
} |
Cela fonctionne car la fonction anonyme copie la valeur de
i dans son argument
arg au moment où elle est appelée, c’est-à-dire au moment où la boucle
for est exécutée.