Pork Center

JavaScript

De Hack-it.org.

(les closures)
m
 
Ligne 56 : Ligne 56 :
// un clic sur la page affichera "body"</javascript>
// un clic sur la page affichera "body"</javascript>
-
=== s'affranchir de '''this''' ===
+
=== S'affranchir de '''this''' ===
Etant donné la différence entre le '''this''' JavaScript et le '''this''' tel qu'il est admis dans d'autres langages orientés objet, beaucoup de programmeurs utilisent ''self'' comme référence à l'objet courant.
Etant donné la différence entre le '''this''' JavaScript et le '''this''' tel qu'il est admis dans d'autres langages orientés objet, beaucoup de programmeurs utilisent ''self'' comme référence à l'objet courant.
Ligne 195 : Ligne 195 :
     }
     }
}</javascript>
}</javascript>
-
 
-
Comme dit plus haut, la ''closure'' contient les variables (dont les paramètres) de la fonction, aussi, au lieu de les passer en paramètres, on peut créer des variables locales :
 
-
 
-
<javascript>function go() {
 
-
    for(var i=0; i<3; i++) {
 
-
        var a = document.createElement('a');
 
-
        a.href = "javascript:";
 
-
        a.innerHTML = "Je dis "+i+" ";
 
-
        (function() {
 
-
            var elem = a;
 
-
            var num = i;
 
-
            elem.addEventListener('click', function() { alert("Je dis "+num); }, false);
 
-
        })();
 
-
        document.body.appendChild(a);
 
-
    }
 
-
}</javascript>
 
-
 
-
Ca revient strictement au même, mais je préfère cette écriture car elle rend évidente ce qu'on souhaite enfermer dans notre nouvelle ''closure'', et surtout, elle montre clairement comment les données sont copiées, problème qu'on va examiner avec l'exemple suivant.
 
=== Les références aux autres ''closures'' ===
=== Les références aux autres ''closures'' ===
Ligne 226 : Ligne 208 :
         a.innerHTML = "Je dis "+i+" ";
         a.innerHTML = "Je dis "+i+" ";
         truc[1] = i;
         truc[1] = i;
-
         (function() {
+
         (function(tablo) {
-
            var tablo = truc;
+
             a.addEventListener('click', function() { alert(tablo.join(" ")); }, false);
             a.addEventListener('click', function() { alert(tablo.join(" ")); }, false);
-
         })();
+
         })(truc);
         document.body.appendChild(a);
         document.body.appendChild(a);
     }
     }
Ligne 244 : Ligne 225 :
-
Pourquoi n'avions-nous pas le problème avec num ? Car quand on a écrit ''num = i'', ''i'' étant un type scalaire entier (''Integer''), JavaScript '''copie''' ''i'' dans ''num''. Si ''i'' valait 1, ''num'' était défini à 1. Les ''Integer'' ne sont pas des '''références''', mais ils contiennent réellement le scalaire entier en eux. Alors que les tableaux sont des '''références''' vers un objet '''Array'''. Pour preuve :
+
Pourquoi n'avions-nous pas le problème avec num ? Car quand on a passé ''i'' à la fonction, ''i'' étant un type primitif (i.e. un nombre, un booléen, une chaîne ou null), JavaScript le passe par valeur, c'est à dire qu'il '''copie''' ''i'' dans ''num''. Si ''i'' valait 1, ''num'' était défini à 1. Les entiers ne sont pas des '''références''', mais ils contiennent réellement le scalaire en eux. Alors que les tableaux sont des '''références''' vers un objet '''Array'''. Pour preuve :
<javascript>var a = [1, 2]; // a est une référence vers un Array contenant [1, 2]
<javascript>var a = [1, 2]; // a est une référence vers un Array contenant [1, 2]
Ligne 251 : Ligne 232 :
alert(a[0]); // 666 !</javascript>
alert(a[0]); // 666 !</javascript>
-
Donc lorsqu'on a écrit ''tablo = truc'', on n'a fait que faire référence au même objet '''Array'''.
+
Donc lorsqu'on passe ''truc'' à la fonction, ''tablo'' fait référence au même objet '''Array''' que ''truc''.
Pour garantir d'avoir un type complexe enfermé dans une ''closure'', il faut faire attention qu'il ne réfère pas à un autre objet, mais qu'il réfère à une copie unique.
Pour garantir d'avoir un type complexe enfermé dans une ''closure'', il faut faire attention qu'il ne réfère pas à un autre objet, mais qu'il réfère à une copie unique.
Ligne 267 : Ligne 248 :
         truc[0] = "Je dis";
         truc[0] = "Je dis";
         truc[1] = i;
         truc[1] = i;
-
         (function() {
+
         (function(tablo) {
-
            var tablo = truc;
+
             a.addEventListener('click', function() { alert(tablo.join(" ")); }, false);
             a.addEventListener('click', function() { alert(tablo.join(" ")); }, false);
-
         })();
+
         })(truc);
         document.body.appendChild(a);
         document.body.appendChild(a);
     }
     }
Ligne 295 : Ligne 275 :
go();</javascript>
go();</javascript>
-
La fonction ''copy'' n'existe pas en JavaScript 1.5 (ni 1.8 il me semble), mais de telles fonctions ont été codées par de nombreux frameworks. C'est ce qu'ils appellent la '''deep copy''', copie profonde d'un objet.
+
La fonction ''copy'' n'existe pas en JavaScript, mais de telles fonctions ont été codées par de nombreux frameworks. C'est ce qu'ils appellent la '''deep copy''', copie profonde d'un objet.
Attention cependant, ces fonctions échouent parfois à copier certains objets de type natif. Par exemple, dans ''JQuery'', copier une expression régulière ne fonctionnera pas, et de manière générale, copier un objet contenant dans ses membres ou sous-membres une ''RegExp'', ''Date'' ou ''Function'' ne fonctionne pas.
Attention cependant, ces fonctions échouent parfois à copier certains objets de type natif. Par exemple, dans ''JQuery'', copier une expression régulière ne fonctionnera pas, et de manière générale, copier un objet contenant dans ses membres ou sous-membres une ''RegExp'', ''Date'' ou ''Function'' ne fonctionne pas.

Version actuelle en date du 2 février 2011 à 06:00