24.1 Créer ses propres objets |
See You Why? |
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.
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 :
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 :
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 :
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'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
.
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 ?
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'.
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à.
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;
}
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
|
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.
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 :
Pour bien comprendre la suite, le lecteur devrait :
* comprendre que le point (0,0) est le coin supérieur gauche de son écran ;
* admettre que l'abscisse sera la distance (en pixels) du bord gauche de l'écran ;
* admettre que l'ordonnée sera la distance (en pixels) du bord supérieur de l'écran et que cette ordonnée est de + en + positive vers le bas (sic!) ;
* lire ces notions graphiques qui seront approfondies dans le chapitre 39 ;
* que toutes les couleurs sont déterminées par des intensités variables des 3 couleurs fondamentales Rouge, Green (Vert) et Bleu ;
* plus de détails à lire dans nos notes relatives au HTML 'couleur de fond'.
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).
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.
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.
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...
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.
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
|
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.
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.
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.
voir suite >>>
voir suite >>>
voir suite >>>
voir suite >>>