Premiers pas en JavaScript
24.1 Créer ses propres objets
cuy copyleft
  See You Why?  

 


Test relatif aux objets prédéfinis (23.9) | | usage des objets propres (24.2)

Contenu

 

 

I. Créer ses propres objets

Avant de commencer ce chapitre, nous rappelons au lecteur qui préfère prendre connaissance des objets prédéfinis de JS, peut pour l'instant abandonner la lecture des deux chapitres qui suivent. On retrouvera ce lecteur au moment où nous présenterons les tableaux ou arrays qui sont des objets JS. Pour les autres, bon courage pour la lecture des deux chapitres suivants.

JavaScript est un langage orienté objet... déjà l'appellation "orienté objet" risque d'effrayer des non initiés ; de plus, JS ne dispose pas de toutes les caractéristiques de la POO (programmation orientée objet). Cependant, nous ne voulons pas ouvrir ici le débat pointilleux relatif à la POO, à l'usage des objets et des méthodes, aux nuances des classes d'objets, à l'héritage de propriétés et des méthodes, etc.

Dans un premier temps, nous voulons calmer la frayeur qui s'installe dans l'esprit du lecteur de nos pages : la manipulation des objets JS n'est pas indispensable pour dynamiser un peu ses pages écrites précédemment en HTML... mais elle pourrait rendre de grands services à ceux qui auront le courage de lire la suite de nos chapitres 24 et 25.

Imaginons différentes professions où l'emploi d'objets personnels ou propres pourrait être utile.
L'instit pourrait utiliser des objets simples de géométrie élémentaire. Quelle simplification de vie s'il pouvait créer un objet "rectangle" qui pourrait avoir deux propriétés sa longueur et sa largeur et qui permettrait l'emploi de méthodes telles que chercher l'aire, chercher son périmètre.

Nous commencerons par vous présenter les deux étapes indispensables à la création d'un objet, à savoir la création d'un constructeur et l'instanciation de nouveaux objets. Nous illustrerons notre propos par deux exemples différents, à savoir un objet "rectangle" avec des propriétés numériques, puis un objet "eleve" (sans accent cet élève) avec des propriétés de divers types.

La création d'un objet se fait en deux temps :

1. il faut créer un 'constructeur' ou déclarer cet objet, c'est-à-dire une fonction particulière qui modélise les objets, qui génère une 'empreinte' générale ou un prototype (nous éviterons l'emploi du terme prototype qui aura un sens particulier en JS et qui désigne une propriété que tout objet acquiert au moment de sa création, un peu comme la propriété length d'une chaine de caractères ou d'un tableau) ; le nom de cette fonction sera le nom de l'objet que nous allons créer et le mot réservé this servira à attribuer les propriétés de cet objet ;

2. puis il faut 'instancier' des objets de ce type en attribuant des valeurs aux propriétés définies lors de la construction de l'empreinte.

On verra ensuite que l'on peut déclarer et instancier simultanément un objet, et enfin, qu'on peut lui attribuer de nouvelles propriétés après sa déclaration initiale.

 

A. création d'un objet 'rectangle'

Nous avions décidé de créer un objet que nous souhaitions appeler 'rectangle'. Nous illustrerons d'abord la manière de créer son empreinte (prototype) par un 'constructeur' et nous souhaitions qu'il ait deux propriétés, à savoir une longueur et une largeur :

 

 

fonction constructeur ou déclaration de l'empreinte

Comme toute fonction, il faudra suivre la syntaxe :

function rectangle(long,larg) {
    //ici viendront les propriétés de l'empreinte de notre objet "rectangle"
}

Pour rappel, en JS, la syntaxe de création d'une fonction est simple :

      1. on écrit le mot réservé function
        (attention avec un U [comme en anglais] et pas un O [comme en français]) ;
      2. on insère une espace ;
      3. on écrit le nom de la fonction constructeur (ici ce sera par exemple "rectangle")
        (à vous de faire preuve d'imagination, mêmes critères que pour les noms de variables :
        1. nom doit commencer par une lettre,
        2. les caractères suivants sont des chiffres, des lettres, des underscores [pas d'espaces],
        3. le nom des fonctions est 'case sensitive', ou sensible à la casse
          attention : lettres non accentuées)
      4. on ouvre et on ferme les parenthèses () sans espace avant,
        et comme on aura deux propriétés, on y note des dénominations provisoires (séparées par des virgules : ici, nous avons choisi de les baptiser provisoirement long et larg) de ces paramètres ;
      5. on place une espace puis l'accolade ouvrante { ;
      6. on incorpore une ligne vierge
        (pour y noter en retrait, les instructions, génératrices des propriétés, chacune terminée par un point-virgule) ;
      7. on place, sur une nouvelle ligne, l'accolade fermante }

Notre étape 6 est restée incomplète... il fallait y indiquer une ou plusieurs instructions que JS puisse exécuter... autant qu'il n'y aura de propriétés pour mon objet. Chaque propriété suivra une syntaxe précise :

      1. le mot clé this suivi d'un point ;
      2. le nom exact de la propriété ;
      3. un signe '=' d'affectation, avec ou sans espace devant ou derrière ;
      4. la valeur que doit prendre cette propriété
        (généralement une constante ou une variable transmise comme paramètre à la fonction) ;
      5. terminer cette instruction par un point-virgule ;
      6. recommencer à a. s'il y a une autre propriété.

Notre constructeur 'rectangle' sera donc créé ainsi :

function rectangle(long,larg) {
    this.longueur = long;
    this.largeur = larg;
}

Le lecteur qui aura cherché d'autres tutoriels JS en aura rencontré une majorité qui proposait les mêmes noms aux paramètres transmis à la fonction (long et larg dans notre exemple) et aux noms des propriétés (longueur et largeur dans notre exemple). C'est permis, mais... bon courage alors pour comprendre ce qui est quoi. Ici, le lecteur comprendra que :
"La propriété 'longueur' de l'objet 'rectangle' est la valeur long transmise comme premier paramètre à la fonction rectangle et sa propriété 'largeur' est la valeur larg transmise comme deuxième paramètre à la fonction rectangle."

Notre constructeur d'objet est maintenant terminé... mais aucun objet de type rectangle n'existe encore. Il nous faudra instancier de nouveaux objets. Exactement comme lors de la création de variable (voir ici), nous avions précisé que la manière la plus correcte de travailler était de distinguer trois moments quant à l'utilisation des variables,
- de la déclarer,
- puis de l'affecter (ou instancier) d'une valeur,
- avant de l'utiliser.
De même pour la création d'objet, nous venons de créer (ou déclarer) son constructeur ou son empreinte, il reste à l'instancier (ou l'affecter de valeurs) puis on pourra l'utiliser.

 

 

l'instanciation d'objets

L'empreinte étant formée, on pourra créer autant d'objets du type rectangle que l'on souhaite. Voici comment créer (ou instancier) 4 nouveaux objets de type rectangle.

    var monRect01 = new rectangle(5,3);
    var monRect02 = new rectangle(25,13);
    var monRect03 = new rectangle(25,33);
    var monRect04 = new rectangle(25.2,13.95);

Syntaxe ?
- mot clé "var" ;
- nom de l'objet (comme pour une variable) ;
- signe d'affectation "=" ;
- mot clé "new" ;
- nom du constructeur de l'objet ;
- suivi immédiatement de parenthèses ;
- qui contiennent les paramètres ou valeurs à attribuer (dans l'ordre de définition du constructeur),
- séparées par des virgules.

Ce dernier exemple est l'occasion d'insister sur l'usage de la virgule comme séparateur de propriétés, mais aussi de l'usage du point décimal (et pas de virgule) pour les valeurs non entières.

Le lecteur attentif fera remarquer que l'exemple monRect03 est erroné car la longueur est plus petite que la largeur... erreur, il aurait fallu faire le test dans le constructeur de la fonction rectangle... trop tard maintenant (voir exercices).

Au début, il peut s'avérer utile de donner des noms particuliers aux objets, par exemple leur donner un nom qui commence par 'o_' qui permettra de distinguer les variables habituelles de celles que nous créons comme objets : on aurait ainsi créer o_monRect01, o_monRect02 , o_monRect03 et o_monRect04.

 

déclaration et instanciation simultanées

Les habitués de la programmation objet en JS déclarent et instancient leurs objets en une étape unique et auraient écrit :

monRect01 = rectangle{longueur:5, largeur:3}
monRect02 = rectangle{longueur:25, largeur:13}
monRect03 = rectangle{longueur:25, largeur:33}
monRect04 = rectangle{longueur:25.2, largeur:13.95}

Caractéristiques de cette nouvelle méthode de création d'objets personnels ?
- pas de mot clé initial var ;
- pas de mot clé new devant le nom générique de l'objet (son prototype) ;
- le nom de la propriété doit être noté et répété à chaque fois ;
- le nom générique est suivi d'accolades qui contiennent ses propriétés ;
- les propriétés sont notées et séparées par des virgules ;
- pour chaque propriété, on note son nom, suivi d'un deux-points, suivi de sa valeur [entre guilles s'il s'agit de valeurs alphanumériques].

Plus facile, me direz-vous ! D'accord, tant que l'on a que 2 propriétés pour chaque objet et que l'on ne travaille qu'avec quelques objets... imaginez 1000 rectangles à créer, vous écrirez 1000 fois le nom de la propriété longueur et 1000 fois celui de la propriété largeur... Plus si convaincu ?

 

 

déclaration de nouvelles propriétés

Dans une séquence suivante, nous montrerons qu'un objet nouvellement créé avec ses propriétés propres peut se voir attribuer de nouveaux attributs (de nouvelles propriétés) en cours de programmation JS. Nos rectangles ont été définis avec 2 propriétés : longueur et largeur ; ils pourraient avoir un périmètre, une surface et/ou une longueur de diagonale, voire une couleur.

Le chapitre suivant nous montrera comment appliquer des méthodes aux objets que nous avons appris à créer. Mais avant cela, créons un autre objet 'eleve'.

 

B. création d'un objet 'eleve'

Si maintenant un enseignant veut créer des objets pour chacun de ses élèves, il lui faudra d'abord réfléchir aux caractéristiques qu'il voudra retenir... en JS, ces caractéristiques seront les propriétés de chaque objet (chaque élève).

Ces propriétés, imaginons qu'elles soient :
- un identifiant unique basé sur une combinaison classe-nom-prénom,
- son nom,
- son prénom,
- sa date de naissance,
- son sexe,
- sa classe.
On pourrait en imaginer bien d'autres, mais arrêtons-nous là.

 

fonction constructeur

Comme pour l'exemple du "rectangle" ci-dessus, il faudra suivre la syntaxe :

function eleve(id,n,pren,dN,sx,cl) {
    //ici viendront les propriétés du prototype de notre objet "eleve"
}

Notre constructeur 'eleve' (ou empreinte) sera donc créé ainsi :

function eleve(id,n,pren,dN,sx,cl) {
    this.id = id;
    this.nom = n;
    this.pren = prenom;
    this.dateNaissance = dN;
    this.sexe = sx;
    this.classe = cl;
}

 

l'instanciation d'objets

Cette empreinte étant définie, on pourra créer autant d'objets du type eleve que l'on souhaite. Voici comment créer (ou instancier) ces nouveaux objets.

    var obba09 = new eleve(obba09,"Obama","Barak",2009,m,rse3);
    var buge01 = new eleve(buge01,"Bush","George",2001,m,res3);
    var clbi93 = new eleve(clbi93,"Clinton","Bill",1993,m,rse3);
    var buge89 = new eleve(buge89,"Bush","Georgia",1989,f,rse3);
    var rero81 = new eleve(rero81,"Reagan","Ronald",1981,m,rse3);
    var caja77 = new eleve(caja77,"Carter","James",1977,m,rse3);
    var foge74 = new eleve(foge74,"Ford","Gerald",1974,m,rse2);
    var niri69 = new eleve(niri69,"Nixon","Ricky",1969,f,rse2);
    var joli63 = new eleve(joli63,"Johnson","Lindon",1963,m,rse2);
    var kejo61 = new eleve(kejo61,"Kennedy","John",1961,m,rse1);
    var eidw53 = new eleve(eidw53,"Eisenhower","Dwight",1953,m,rse1);
    var trha45 = new eleve(trha45,"Truman","Hairy",1945,f,rse1);

Le lecteur comprendra pourquoi nous n'avons pas voulu être sexiste et avons dû massacrer un peu les nom ou prénom de certain(e)s élèves ;o).

J'aurais même pu écrire en suivant la méthode Jason (voir plus bas):

    var moha17 = {};

ce qui aurait été identique à:

    var moha17 = new Object();

Ces deux notations créent un objet moha17, qui sera reconnu comme objet, mais tout-à-fait indéterminé pour l'instant.

À contrario, si j'écrivais:
    var moha17 = new eleve();
je créerais un nouvel objet, qui répondrait à l'empreinte eleve() et qui en possèderait donc les 6 propriétés, sans que celles-ci ne soient déterminées. moha17 possèderait donc les propriétés id, nom, pren, dateNaissance, sexe, classe dont aucune ne sera définie.

Par contre, en tant qu'objet créé, moha17 possèdera aussi, comme tout objet, les propriétés prototype, constructor et toString.

Exemple

<html>
<body>

<h1>constructeur d'ojet</h1>
<script type="text/javascript">
//constructeur de l'empreinte
function eleve(id,n,pren,dN,sx,cl) {
    this.id = id;
    this.nom = n;
    this.prenom = pren;
    this.dateNaissance = dN;
    this.sexe = sx;
    this.classe = cl;
}
//instanciation
    var obba09 = new eleve(obba09,"Obama","Barak",2009,m,rse3);
    var buge01 = new eleve(buge01,"Bush","George",2001,m,res3);
    var clbi93 = new eleve(clbi93,"Clinton","Bill",1993,m,rse3);
    var buge89 = new eleve(buge89,"Bush","Georgia",1989,f,rse3);
    var rero81 = new eleve(rero81,"Reagan","Ronald",1981,m,rse3);
    var caja77 = new eleve(caja77,"Carter","James",1977,m,rse3);
    var foge74 = new eleve(foge74,"Ford","Gerald",1974,m,rse2);
    var niri69 = new eleve(niri69,"Nixon","Ricky",1969,f,rse2);
    var joli63 = new eleve(joli63,"Johnson","Lindon",1963,m,rse2);
    var kejo61 = new eleve(kejo61,"Kennedy","John",1961,m,rse1);
    var eidw53 = new eleve(eidw53,"Eisenhower","Dwight",1953,m,rse1);
    var trha45 = new eleve(trha45,"Truman","Hairy",1945,f,rse1);
//utilisation
      document.write(kejo61+"<br>");
      document.write(kejo61.nom+"<br>");
      document.write(moha17+"<br>");
//      document.write(moha17.nom+"<br>");     //déactiver cette ligne provoquera une erreur...                                                                                         //difficilement trouvable

    var moha17 = {};
      document.write(moha17+"<br>");
      document.write(moha17.nom+"<br>");

    var moha17 = new eleve();
      document.write(moha17+"<br>");
      document.write(moha17.nom+"<br>");

</script>

</body>
</html>

 

Si vous avez lu jusqu'ici, sans réagir, vous avez eu tort... je suis cependant certain que tous nos lecteurs auront remarqué que toute donnée non numérique (et ici seule l'année de naissance pourrait être considérée comme numérique...), toute donnée non numérique devrait être notée entre guilles, ce qui n'a pas été fait ci-dessus, mais a été fait si vous avez essayé par notre testeur de code.

 

C. création d'un autre objet nRect dont les propriétés sont des objets

Si dans notre développement, nous avions décidé de définir 'rectangle' par deux propriétés 'longueur' et 'largeur', rien n'a été dit concernant sa position sur l'écran ni concernant sa couleur... :-(

Rien n'empêche le programmeur d'être plus précis et de définir un rectangle par 3 propriétés :

Le lecteur aura dès lors compris que :

Cela signifie donc que nRect sera un objet JS dont chaque propriété sera elle-même un objet JS.

On définira ainsi l'empreinte des objets de type point (dénommé pt) et couleur (dénommé kleur ici) :

function pt(absc,ordo) {
    this.x = absc;
    this.y = ordo;
}
 

function kleur(rr,gg,bb) {
    this.rouge = rr;
    this.vert = gg;
    this.bleu = bb;
}
 

L'empreinte de ces deux objets et leurs propriétés étant définies, on est en mesure de pouvoir définir l'empreinte de l'objet nRect souhaité via ce constructeur :

function nRect(A,B,KL) {
    this.hg = A;
    this.bd = B;
    this.coul = KL;
}
 

Les déclarations sont faites via les constructeurs, il ne reste plus qu'à intancier les objets dans le bon ordre :

var ptA = new pt(135,178);
var ptB = new pt(455,654);
var k_orangefonce = new kleur("ff","8c","00");
var nouveauRectangle = new nRect(ptA,ptB,k_orangefonce);
 

On aurait aussi pu écrire :

var nouveauRectangle2 = new nRect(pt(143,169),pt(460,567),kleur("79","c6","9d"));

Le lecteur aura tout avantage à retenir absolument ceci :

Le mot-clé new ne signifie pas « créer un nouvel objet »,
mais signifie « créer une nouvelle instance de l'objet »,
ce qui est très différent car dans le second cas on ne fait que créer une instance, une copie, de l'objet initial,
ce qui nous permet de conserver l'objet initial en question (ou son empreinte intacte).

 

D. création d'objet, attention aux variantes proposées

Si vous avez lu notre introduction concernant les objets informatiques, vous aurez retenu que JS n'a pas toutes les caractéristiques des objets généralement utilisés dans les autres langages de POO.

 

JavaScript ne possède pas de classe

JS ne possède pas de classes d'objets. Cependant, certains auteurs de tutoriels affirment que le constructeur de l'objet est la classe d'objet. On peut même lire que 'la nouvelle classe d'objets «hérite» des propriétés et méthodes de sa « mère ».' Ceci est aberrant car si le constructeur crée un plan prototype des objets qui seront instanciés, chaque objet pourra avoir ses propres propriétés. JavaScript n'a d'ailleurs prévu aucun mot clé pour la créer.
Par contre, JS utilise les mots clés
new
pour créer une nouvelle instance d'un objet (donc une nouvelle copie de cet objet),
Array
pour créer un objet de type tableau (voir chapitres 26 à 32),
Date
pour créer des objets de type date (voir chapitre 35),
Math
pour manipuler des objets de type mathématique (voir chapitre 34),
var
pour créer des objets de type variable, déjà connue depuis longtemps (voir chapitre 3 et suivants),
function
pour la création de série d'instructions à exécuter (voir chapitre 6 et suivants),
la balise HTML <form> pour la création des formulaires, et nous négligerons ici tous les éléments que peuvent comprendre les formulaires.

JavaScript ne fait pas la différence entre une classe et une instance comme Java : il n'y a pas de définition de classe, tous les objets sont des instances.

 

la fonction constructeur d'un objet n'est pas une classe

Ce n'est pas parce qu'une société de construction vous propose des structures prototypes de constructions ou plans types, que votre maison existe... certes, elle sera conforme à l'ossature proposée, mais libre à vous de changer l'usage des pièces, les matériaux utilisés, le type de menuiserie à y installer, les luminaires et tout le reste qui fera que votre maison sera bien la vôtre avec ses caractéristiques propres.
Ce n'est qu'en instanciant chaque propriété qu'un objet commence à exister.

Ce n'est pas parce que je fais la liste de caractéristiques d'une moto que je crée une classe de motos... certes, elle aura une marque, un modèle, une cylindrée, une puissance du moteur, une couleur, une immatriculation, un proprio, etc., mais ce n'est que lorsque j'aurai précisé chaque caractéristique pour l'objet baptisé "moto_GVdK" que cet objet commencera à exister.
Sa marque sera "BMW", son modèle sera "R1200RT", sa cylindrée "1200cc", sa puissance moteur "110ch" (seulement 100ch en France), sa couleur "grise", etc. et en continuant à donner des valeurs à chacune de ses propriétés, je décrirai un objet unique qui sera instancié... la "moto_GVdK".

De même, ce n'est pas parce que tous vos élèves ont un identificateur unique, un nom, un prénom, une date de naissance, un sexe que vous venez d'engendrer une classe d'élèves... ce n'est que lorsque chaque élève se sera vu attribuer des valeurs pour chaque propriété qu'il commencera à exister au point de vue informatique... il faut que chaque objet soit instancié conformément aux propriétés que l'on souhaite voir apparaitre sur sa fiche...

 

le mot-clé "this" en JS

On montrera que ce mot-clé "this" désigne l'objet en cours de traitement dans un constructeur ou une méthode. De ce fait il est possible d'avoir accès à tous les attributs (ou propriétés) et méthodes de l'objet dans le code d'une fonction.
Ce "this" peut aussi désigner un événement ou un élément d'événement.

Ce mot clé sera précisé dans le chapitre suivant.

 

création d'un objet par la méthode JSON

Il est possible de créer un objet sans la lourdeur engendrée par la création d'un constructeur. Cette méthode s'appelle JSON pour "JavaScript Object Notation". La simple écriture suivante permet de créer un objet qui n'a pas encore de propriétés ni de méthodes :

var Json_Client01= {};

Pour lui attribuer des propriétés (ce que l'on peut faire en une seule instruction), on écrira :

var Json_Client01= {
   "nom":"Jules Tartempion",
   "rue":"avenue de la forge 39",
   "age":33,
   "tel":"32 65 123456"
};

Et si l'on maitrise bien les balises <span> du HTML, voici un exemple d'utilisation :

 

Exemple

<html>
<head>
<title>notation objet JSON</title>
</head>

<body>
<p>
<b>Nom</b> : <span id="jname"></span><br>
<b>Age</b> : <span id="jage"></span><br>
<b>Adresse</b> : <span id="jstreet"></span><br>
<b>Téléphone</b> : <span id="jphone"></span><br>
</p>

<script type="text/javascript">
var Json_Client01= {"nom":"Jules Tartempion",
    "rue":"avenue de la forge 39",
    "age":33,
    "tel":"32 65 123456"
};
var Json_Client02= {"nom":"G. Zucri",
    "rue":"rue du paradis 1",
    "age":33,
    "tel":"32 2 7654321"
};
document.getElementById("jname").innerHTML=Json_Client02.nom;
document.getElementById("jage").innerHTML=Json_Client02.age;
document.getElementById("jstreet").innerHTML=Json_Client02.rue;
document.getElementById("jphone").innerHTML=Json_Client02.tel;
</script>

</body>
</html>


Le lecteur notera cependant que cette notation ne sera allégée que si l'on ne fait appel qu'à quelques objets de même nature (à quelques instances), car il faut à chaque fois noter les propriétés en long et en large.

 

l'objet prototype

JavaScript propose la notion d'objet prototype. Tout objet dispose d'un objet prototype possédant toutes les propriétés constantes communes à toutes les instances de l'objet (certains diront la classe, mais...), propriétés dont il hérite au moment de sa création. Nous y reviendrons dans une séquence suivante de ce chapitre.

 

rappel de l'essentiel

Une instance d'objet se crée comme une variable à laquelle on affecte le mot-clé new suivi du nom de son constructeur.

Le constructeur se crée comme une fonction dont chaque paramètre est introduit par this. suivi du nom du paramètre qui sera le nom de la propriété et dont la valeur sera celle du paramètre de la fonction.

Une méthode se crée aussi comme une fonction, mais construite comme une propriété introduite par le mot-clé this et dont la valeur affectée sera une fonction avec des instructions et un return.

Les méthodes sont véritablement dédiées pour opérer sur l'objet les contenant en tant que propriété, alors que les fonctions sont totalement dissociées des objets.

Un constructeur est l'empreinte d'un objet, qui définit comment chaque instance doit être définie. Plusieurs instances d'un même objet défini par un constructeur peuvent coexister.

 

 

II. Utiliser ses propres objets

voir suite >>>

 

 

III. Ajouter des propriétés à ses propres objets

voir suite >>>

 

 

VIII. Exercices relatifs à la création d'objets propres

voir suite >>>

 

IX. Test relatif à la création d'objets propres

voir suite >>>

 

 


Test relatif aux objets prédéfinis (23.9) | | usage des objets propres (24.2)