JavaScript est un langage considéré comme orienté objet bien qu'il n'en ait pas toutes les caractéristiques.
Ce chapitre est peut-être difficile pour les débutants mais - qu'ils se rassurent - les notions évoquées ici ne sont utiles qu'à un stade de programmation avancée ; il est possible de s'en passer dans la plupart des cas à traiter en HTML dynamique ; les objets peuvent néanmoins rendre de grands services pour les applications complexes.
Il faut au moins comprendre le sens des termes de base décrits dans ce paragraphe car ils seront utilisés dans la suite du document.
D'abord, qu'est-ce qu'un objet pour le programmeur ? En programmation traditionnelle on écrit des séquences de programmes qui utilisent et modifient des données. Il n'y a aucun contrôle de l'opportunité d'usage de ces données ; ça n'aurait par exemple aucun sens de prendre la racine carrée d'un numéro de téléphone ! Or tous les programmeurs font des erreurs - c'est inévitable et fait partie du métier. La programmation traditionnelle ne permet pas de détecter ce genre d'erreur car elle ignore la nature des données. Tout au plus permet-elle - comme en langage Pascal - de différencier les types de données (numériques, chaînes de caractères, etc.).
En programmation objet, on ne manipule plus des données indifférenciées mais des «objets». Un objet appartient à une «classe d'objets» qui est l'ensemble des objets possédant en commun les mêmes caractéristiques et traitements. Ces caractéristiques sont appelées «propriétés» et ces traitements sont appelés «méthodes».
Les seules parties d'un objet «visibles» de l'extérieur sont ses propriétés.
Un objet ne peut être manipulé qu'à l'aide des méthodes de la classe à laquelle il appartient. Certaines propriétés ne sont visibles que par l'intermédiaire de méthodes de la classe de l'objet.
Prenons comme exemple une classe d'objets informatique que vous connaissez : la fenêtre. Que peut-on faire d'une fenêtre au niveau programme ? La déplacer, la redimensionner, la remplir, la faire disparaître, etc. - mais il n'est pas question de prendre sa racine carrée !
Supposons que nous voulions définir une classe d'objets appelée «fenêtre» ; nous lui donnerons les propriétés longueur, largeur, position gauche et hauteur dans l'écran (entre autres) ; nous définirons également pour elle des méthodes telles que «redimensionnement», «déplacement» et «disparition»...
Afin d'éviter toute confusion par la suite, il convient de bien distinguer une «classe d'objets» et une «occurrence d'objet» ou simplement «objet» : Une fenêtre est - pour le programmeur - une classe d'objets et la présente fenêtre est une occurrence de l'objet. Lorsqu'on va définir une fenêtre en tant que classe d'objets on va fournir les propriétés valables pour toutes les fenêtres. Lorsqu'on va définir la fenêtre courante on va fournir les propriétés valables seulement pour cette fenêtre.
Certains objets et classes d'objet ainsi que les propriétés et méthodes associés sont pré-définis.
Certaines opérations n'auront pas le même sens selon les objets manipulés ; ainsi le signe «+» ; entre deux nombres il permet de les additionner ; entre deux chaînes de caractères il permet de les juxtaposer. Le signe «+» peut être considéré comme une méthode prédéfinie des objets de type chaînes de caractères.
On peut définir une classe d'objets à partir d'une classe existante. La nouvelle classe d'objets «hérite» des propriétés et méthodes de sa «mère».
Lorsqu'on met au point un programme JavaScript on rencontre souvent cette erreur irritante :
«"nomObjet" n'est pas un objet
».
Ceci signifie simplement que «nomObjet
» n'est pas reconnu en tant qu'objet JavaScript
par l'interpréteur.
Un objet isolé est désigné par son nom, comme toute variable.
Un objet peut contenir d'autres objets. Par exemple, le document HTML dans lequel figure votre script JavaScript est désigné par «document» et est un sous-objet de la fenêtre - désignée par «window» - affichée lorsque ce script se déroule.
Un sous-objet ou une propriété est désigné par son nom, précédé d'un point, précédé du nom de l'objet.
Une méthode est désignée par l'appel de la fonction correspondante, précédé d'un point, précédé du nom de l'objet.
Si le sous-objet, la propriété ou la méthode n'appartient pas à la classe de l'objet désigné, l'interpréteur signale une erreur.
nbSaisi
» de l'objet «formul
»
est désigné par «formul.nbSaisi
».value
» du sous-objet «formul.nbSaisi
»
est désignée par «formul.nbSaisi.value
».charAt
» de la classe d'objets «String
»,
appliquée à la chaîne «ch
», avec le paramètre «10
»,
est désignée par «ch.charAt(10)
».Une classe d'objets peut être définie par le programmeur à l'aide d'une méthode particulière appelée «constructeur». Le constructeur va servir à créer des occurrences d'objets de sa classe et à affecter des valeurs initiales aux propriétés des objets créés.
Il est écrit sous la forme d'une procédure. A l'intérieur de celle-ci, l'objet traité est désigné par le mot clé this pour utiliser ses propriétés ; this signifie «cet objet».
La fonction ci-dessous permet de définir la classe d'objets clasRect
décrivant un rectangle. Lorsqu'elle sera appelée elle initialisera
les caractéristiques du rectangle traité.
function clasRect(parX, parY, parL, parH)
{
this.propX = parX; // coordonnées du rectangle
this.propY = parY;
this.propL = parL; // dimensions du rectangle
this.propH = parH;
}
Les principales classes d'objet JavaScript prédéfinies sont Array, Boolean, Date, Function, Global, Math, Number, Object, et String.
Une nouvelle occurrence d'une classe d'objets - fournie par le système ou définie par le programmeur - est une variable définie à l'aide du mot clé new suivi de l'appel au constructeur associé à la classe d'objets.
[var] nomObj1
= new
constructeur(paramètre,...)
;
Création de deux rectangles nommés objR1
et objR2
.
Ces rectangles sont des occurrences de la classe d'objets clasRect
dont on utilise le
constructeur.
var objR1 = new clasRect(100, 200, 300, 400);
var objR2 = new clasRect(250, 350, 450, 150);
Si l'occurrence d'objet a été définie avec le mot clé var, sa durée de vie est limitée par celle du bloc d'instructions dans lequel elle a été créée (comme toute variable explicitement définie). Il n'y a pas d'autre moyen de la supprimer. Une occurrence d'objet déclarée avec le mot clé var au niveau global (hors de tout bloc) ne sera donc supprimée qu'à la fin du déroulement du script.
Si l'occurrence d'objet a été définie sans le mot clé var (variable visible de tout le programme) il est possible de la supprimer à l'aide du mot clé delete.
delete nomObjet
La phrase précédente rend une valeur booléenne. Cette valeur est true si la suppression a réussi, false sinon. La suppression échouera - notamment - si l'objet a été créé à l'aide de var.
Pour effectuer un traitement déterminé sur les objets d'une classe donnée - fournie par le système ou définie par le programmeur - il faut disposer d'une méthode adaptée.
Pour définir une méthode il est nécessaire d'associer son nom à la fonction ou procédure qui effectue ce traitement. Cette association est effectuée à l'aide du mot clé prototype.
Comme dans le cas du constructeur l'objet traité est désigné - à l'intérieur de la fonction - par le mot clé this pour utiliser ses propriétés.
nomClasse
.prototype.nomMethode = nomFonction
;
On définit la méthode nomMethode
de la classe nomClasse
avec le traitement de la fonction nomFonction
.
Notez l'absence de parenthèses derrière le nom de la fonction. En effet, si on plaçait les parenthèses, la fonction serait effectuée et c'est son résultat qui serait fourni et non son nom.
La méthode methSurf
ci-dessous permet de calculer
la surface d'un objet de classe clasRect
décrivant un rectangle.
Les dimensions du rectangle sont données par ses propriétés propL
et propH
.
clasRect.prototype.methSurf = foncSurf;
function foncSurf()
{
return this.propL * this.propH;
}
Utilisation de la méthode methSurf
pour calculer la surface du rectangle objR1
:
var surfRect1 = objR1.methSurf();
Une nouvelle propriété peut être ajoutée à une occurrence d'un objet - fournie par le système ou définie par le programmeur. La classe d'objets n'est pas modifiée. Cet ajout est effectué automatiquement lorsqu'on affecte une valeur à cette propriété.
Je désire ajouter une propriété appelée couleur
à l'objet rectangle objR1
:
objR1.couleur="rouge";
Cette facilité est une source d'erreur difficile à localiser ; si on fait une faute de frappe sur le nom d'une propriété que l'on désire modifier, JavaScript considère qu'on en crée une nouvelle...
Il est possible de supprimer des propriétés d'une occurrence d'objet si elles ont été créées par le programmeur. Cette suppression s'effectue à l'aide du mot clé delete (comme pour un objet).
delete nomPropriete
La valeur de l'expression booléenne ci-dessus est true si la suppression a réussi, false sinon. La suppression échouera - notamment - si la propriété n'a pas été créé par le programmeur.
Comme nous l'avons vu, le mot clé this désigne l'objet en cours de traitement dans un constructeur ou une méthode.
Si aucun objet n'est en cours de traitement, this désigne l'objet window (la fenêtre courante).
Utilisé dans un élément HTML (traitement d'un événement) il désigne cet élément.
<INPUT type=button value="paroles" onclick="traitement(this.value);">
<INPUT type=button value="musique" onclick="traitement(this.value);">
Les deux boutons renvoient au même traitement mais le titre du bouton est fourni à la procédure de traitement.
L'instruction with permet de rationnaliser l'écriture d'une séquence de programme en évitant de répéter le nom d'un objet. Ce nom peut en effet être omis dans le champ d'action de cette instruction.
with (nomObjet
) instruction
L'instruction peut être un bloc d'instructions.
Nous allons écrire la même instruction sans, puis avec with. L'objet «Math» utilisé sera étudié ultérieurement.
Sans with :
sinAplusB = Math.sin(A)*Math.cos(B)+Math.cos(A)*Math.sin(B);
Avec with :
with (Math) sinAplusB = sin(A)*cos(B)+cos(A)*sin(B);
Nous avons pris soin dans ces exemples de donner des noms différents aux méthodes et aux fonctions associées afin de faciliter la compréhension des mécanismes de gestion des objets. Dans la pratique on peut donner le même nom à ces deux entités.
C'est le regroupement des exemples cités plus haut.
// constructeur classe d'objets rectangle
function clasRect(parX, parY, parL, parH)
{
this.propX = parX; // coordonnées du rectangle
this.propY = parY;
this.propL = parL; // dimensions du rectangle
this.propH = parH;
}
// fonction associée à méthode de calcul surface objet rectangle
function foncSurf()
{
return this.propL * this.propH;
}
// Création de deux rectangles
var objR1 = new clasRect(100, 200, 300, 400);
var objR2 = new clasRect(250, 350, 450, 150);
// définition de la méthode de calcul de surface
clasRect.prototype.methSurf = foncSurf;
// affectation de la nouvelle propriété «couleur»
objR1.couleur = "rouge";
objR2.couleur = "verte";
var libel;
libel = "Rectangle 1"; // affichage des propriétés du rectangle 1
libel += " - Position : " + objR1.propX + "," + objR1.propY;
libel += " - Dimensions : " + objR1.propL + "," + objR1.propH;
libel += " - Surface : " + objR1.methSurf();
libel += " - Couleur : " + objR1.couleur;
alert(libel);
// suppression couleur 2e objet (elle apparaîtra «undefined»)
alert("Résultat suppression couleur rectangle 2 : " + delete objR2.couleur);
libel = "Rectangle 2"; // affichage des propriétés du rectangle 2
libel += " - Position : " + objR2.propX + "," + objR2.propY;
libel += " - Dimensions : " + objR2.propL + "," + objR2.propH;
libel += " - Surface : " + objR2.methSurf();
libel += " - Couleur : " + objR2.couleur;
alert(libel);
// Définition de la classe d'objets «oCompte»
// représentant un compte bancaire
function oCompte(Nom, Solde)
{
// Définition de la propriété «Nom du titulaire»
this.Nom = Nom;
// Définition de la propriété «Solde du compte»
this.Solde = Solde;
}
// Définition de la fonction «Créditer le solde du compte»
function fCrediter(Montant)
{
// On modifie la propriété «Solde du compte»
this.Solde += Montant;
}
// Définition de la fonction «Débiter le solde du compte»
function fDebiter(Montant)
{
// On modifie la propriété «Solde du compte»
this.Solde -= Montant;
}
// Définition de la fonction
// «Afficher les propriétés de l'objet oCompte»
function fAfficher()
{
alert(this.Nom + " possède " + this.Solde + " FF");
}
// Définition des méthodes «Credite», «Debite» et «Affiche»
// en associant les prototypes des fonctions
// «fCrediter», «fDebiter» et «fAfficher»
// à la classe d'objets «oCompte»
oCompte.prototype.Credite = fCrediter;
oCompte.prototype.Debite = fDebiter;
oCompte.prototype.Affiche = fAfficher;
// Création de deux comptes bancaires
// (occurrences de l'objet «oCompte»)
CompteB = new oCompte("Bernard", 10000);
CompteE = new oCompte("Eric", 15000);
// Utilisation des méthodes de la classe «oCompte»
// pour manipuler ses objets
CompteB.Affiche();
CompteE.Affiche();
CompteB.Credite(1500);
CompteE.Debite(10000);
CompteB.Affiche();
CompteE.Affiche();
CompteB.Debite(5000);
CompteE.Credite(1500);
CompteB.Affiche();
CompteE.Affiche();