Premiers pas en JavaScript
25.1 Méthodes et objets propres
cuy copyleft
  See You Why?  

 


test relatif aux objets propres et leurs propriétés(24.9) | | Attribution de méthodes hors constructeur (25.2)

Contenu

 

 

I. Attribuer des méthodes à ses objets propres

Dans le chapitre précédent, nous avons appris à créer des objets JS et à leur attribuer des propriétés. Une des particularités et un des avantages des objets est que l'on peut leur attribuer des méthodes (fonctions) qui leur sont propres. Inutile de vous rappeler que pour des objets prédéfinis de JS, il existait déjà des méthodes. Songeons à la méthode write() applicable à l'objet document... on pouvait lire document.write("Salut la compagnie"). Mais cela concernait l'usage des méthodes relatives à des objets prédéfinis de JS. Après avoir appris à définir des objets propres dans le chapitre précédent, notre propos ici est d'apprendre à leur attribuer des méthodes.

Dans le chapitre précédent, nous avons montré que nous pouvions utiliser les objets avec leur(s) propriété(s) comme des noms de variables... par exemple, on pouvait écrire :

aireRect02 = monRect02.longueur * monRect02.longueur;

mais programmer cette instruction n'est valable que pour le calcul de l'aire de notre Rectangle02 et, s'il y a lieu de calculer plusieurs aires de rectangles, bon courage pour répéter cette instruction pour chacun des rectangles étudiés. La force de JS et de ses objets est qu'il est possible d'adapter et d'attribuer des méthodes qui soient applicables à toutes les instances d'un même objet. Comment faire ?

A. attribution de méthode dans le constructeur rectangle()

En construisant le 'prototype', l' 'empreinte' de l'objet, il est facile de lui ajouter des méthodes. Rappelons d'abord le constructeur (sans méthodes) de nos rectangles. La syntaxe correcte de notre constructeur rectangle était :

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

Et, puisque nous savons qu'une méthode est une fonction applicable à toutes les instances d'un objet, il nous parait logique de la déclarer à l'intérieur du constructeur. Ainsi, pour ajouter une méthode qui calcule l'aire de n'importe quel rectangle ainsi défini, on écrira :

function rectangle(long,larg) {
    this.longueur = long;
    this.largeur = larg;
    this.aire = function() {
        var s = this.longueur * this.largeur;
        return s;
    }

}

Et voilà la syntaxe pour attribuer une méthode à un objet, dans son constructeur. Il suffira alors d'utiliser cet objet de la manière suivante :

var mon_rect1 = rectangle(6,4);
document.write(mon_rect1.aire);
et votre ordi répondra gentiment 24 ;o)

B. attribution de méthode dans le constructeur eleve()

De la même façon, on pourrait définir une méthode pour notre constructeur eleve(). Chaque élève s'est vu attribuer une propriété qui est sa date de naissance [en réalité, la date d'entrée en fonction de chacun des présidents], on pourrait attribuer une méthode qui calcule et affiche l'age [en réalité, le nombre d'années depuis l'entrée en fonction] ou une autre qui affiche les infos de chaque élève...

De la même manière que dans notre exemple précédent, dans la création du constructeur, on peut envisager de créer ces méthodes. On pourrait écrire :

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;
    this.afficherAge = function() {
        var aujourdhui = new Date();
        var an_aujourdhui = aujourdhui.getFullYear();

        var age = an_aujourdhui - dN;
        document.write("Il y a " + age + " que "+ this.nom + " est entré dans ce bas monde");
    }
    this.afficherInfos = function () {
        alert(this.eleve.prenom + " " + this.eleve.nom + " de sexe "+ this sexe +
             " a comme identificateur " + this.id +"./n");
    }
}

En gros, en créant un objet, on peut incorporer dans le constructeur la propriété-fonction d'autres propriétés de cet objet, la méthode, elle aussi introduite par le mot clé this. Cela alourdit fortement la mémoire de l'ordinateur, puisque chaque instance de l'objet rectangle aura cette nouvelle propriété-méthode.

Pour palier à cet inconvénient, beaucoup de programmeurs en JS préfèrent définir des méthodes hors constructeur, mais ils abandonnent alors la programmation dite "objet". C'est ce que nous aborderons dans la séquence suivante. En fait, ils créent une fonction ordinaire en lui passant comme seul paramètre un objet... ce qui est une programmation utilisant les objets sans être de la programmation orientée objet ;o) ... voir séquence suivante.

 

C. variante : méthode annoncée dans le constructeur et définie en dehors

Certains préfèrent la construction suivante des méthodes définies dans le constructeur, mais dont la fonction est définie hors constructeur. Aujourd'hui, je n'ai pas encore pu distinguer les avantages et inconvénients de chaque syntaxe... je vous tiendrai au courant dès que possible.

Voici donc la variante sur le même exemple que ci-dessus :

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;
    this.afficherAge = afficherAge;
    this.afficherInfos = afficherInfos;
}

function afficherAge() {
        var aujourdhui = new Date();
        var an_aujourdhui = aujourdhui.getFullYear();

        var age = an_aujourdhui - dN;
        document.write("Il y a " + age + " que "+ this.nom + " est entré dans ce bas monde");
}
function.afficherInfos() {
        alert(this.eleve.prenom + " " + this.eleve.nom + " de sexe "+ this sexe +
             " a comme identificateur " + this.id +"./n");
}

D. attribution de méthode via le prototype

Nous savons maintenant que :

Nous emploierons encore ce prototype pour attribuer une méthode à un objet. 

Rappelons-nous qu'il est possible de créer un nouvel objet 'o_Personne' qui aura deux propriétés (son nom et son prénom) de la manière suivante (par son constructeur) :

function o_Personne(p_n,p_pr) {
    this.nom = p_n;
    this.prenom = p_pr;
}

Nous avons déjà utilisé prototype pour attribuer des propriétés à nos objets, voilà maintenant comment utiliser prototype pour attribuer une méthode (donner1Nom), sans oublier qu'une méthode est une fonction propre à des objets :

o_Personne.prototype.donner1Nom = function () {
    return this.nom;
};
 

Déjà sans cette méthode ajoutée, on pouvait instancier quelques o_Personne (s) :

var fd = new o_Personne("Del","Fred");
var sf = new o_Personne("Far","Sih");
 

Puisque nous avons défini l'empreinte de nos objets (constructeur), ainsi que défini une méthode sur cette empreinte (donner1Nom) et instancié deux objets, essayons de les utiliser. On écrira, par exemple :

document.write("essai 1 : "+fd.donner1Nom()); qui affichera à l'écran essai 1 : Del que j'aurais d'ailleurs pu obtenir sans usage d'une méthode en écrivant simplement l'instruction document.write("essai 1 : "+fd.nom); mais alors vous n'auriez pas vu comment créer ni utiliser une méthode pour un objet.

Créons maintenant une deuxième méthode, à peine plus sophistiquée, qui placera le nom dans une courte phrase et qui emploiera la méthode précédemment définie. La syntaxe sera la même :

o_Personne.prototype.direSonNom = function () {
    "Salut, mon nom est : " + this.donner1Nom();
};
  

On pourrait tester cette nouvelle méthode sur chacune des instances (fd et sf) de l'empreinte o_Personne. On écrirait alors :

document.write("<br>essai 2 : "+fd.direSonNom());
document.write("<br>essai 3 : "+sf.direSonNom());

Je ne vous ferai pas l'affront de vous écrire en long et large ce qui serait affiché à l'écran suite à ces instructions.
Créons maintenant une deuxième empreinte, proche de la précédente et à travers laquelle nous essaierons d'illustrer les classes, sous-classes et héritages dont parlent certains tutoriels, mais qui n'existent pas en JS...

Un nouveau constructeur :
function o_Etudiant(p_n,p_pr) {
    this.nom = p_n;
    this.prenom = p_pr;
}

Et comme mes étudiants sont des personnes (déjà définies), je dirai que mes étudiants ont la même empreinte que les personnes. J'écrirai :

o_Etudiant.prototype = new o_Personne();

Ceci étant précisé, nous allons tester si un nouvel étudiant (instancié) peut être affecté d'une méthode que l'on a définie sur les personnes... il faut donc d'abord instancier un étudiant non défini comme personne, puis nous lui affecterons la méthode direSonNom définie pour des personnes. On écrira :

var gp = new o_Etudiant("Pal","Gio");
document.write("<br>essai 4 : "+gp.direSonNom());
 

Le lecteur attentif se doutera que l'écran affichera le message :
essai 4 : Salut, mon nom est : Pal et il a raison.

Et, pour voir si nous avons bien compris comment définir des méthodes, nous en créerons deux sur l'empreinte o_Etudiant.
La première meDevoir() qui fixera un montant dû par étudiant en début d'année, en lui attribuant une nouvelle propriété montantdu.
La seconde meDevra() qui calculera le montant dû augmenté de 10 % si l'étudiant n'a pas payé pour la fin de l'année académique [Je ne tolérerai aucun commentaire... mais c'est plus facile à calculer].

En voici la source :
o_Etudiant.prototype.meDevoir = function(du) {
    this.montantdu = du;
}
o_Etudiant.prototype.meDevra = function() {
    var duFutur = 1.1*this.montantdu;
    return duFutur;
}

Attention ici à deux risques fréquents d'erreurs :
* ne jamais utiliser meDevra avant d'avoir utilisé meDevoir... comment voulez-vous recalculer le montant dû en fin d'année si vous ne connaissez pas celui de la dette de l'étudiant avant cette fin d'année ?
* ne pas oublier d'affecter les instances de votre 'empreinte' o_Etudiant d'une valeur de la propriété montantdu par la méthode meDevoir().

Dans l'ordre, on devra écrire :
gp.meDevoir(200);
avant de tester :
document.write("<br>essai 5 : "+gp.prenom+" "+gp.nom+" me devra en fin d'année : "+gp.meDevra()+" euros.");
qui affichera à l'écran :
essai 5 : Gio Pal me devra en fin d'année : 220.00000000000003 euros.

C'est un exemple des erreurs d'arrondis que JS fait et dont je vous avais parlé dans la séquence des "variables numériques", mais avouez que l'erreur est minime.

Cet affichage ne prouve qu'une seule chose : la méthode écrite pour des objets de type o_Etudiant fonctionne correctement. Il ne nous reste plus qu'à tester si ces méthodes définies pour o_Etudiant fonctionneront sur o_Personne... Allons-y pour le test :

//document.write("<br>ici");
sf.meDevoir(150);
document.write("<br>essai 6 : "+sf.prenom+" "+sf.nom+" me devra en fin d'année : "
       +sf.meDevra()+" euros.");
 

Le lecteur attentif s'étonnera de ne rien voir apparaître et c'est normal... meDevoir est une méthode définie sur o_Etudiant, mais pas sur o_Personne.
On a bien dit que les étudiants avaient la même empreinte que les personnes, mais on n'a jamais dit que les personnes devaient calquer leur empreinte sur celle des étudiants. Ce qui est normal,
puisque tout étudiant est une personne, mais
toute personne n'est pas étudiant(e)
.

C'est là que des créateurs de tutoriels justifient que la classe des étudiants héritent des méthodes et propriétés de la classe des personnes... mais rappelons que, contrairement aux langages Java, JS ne travaille pas avec des classes ni des sous-classes et que l'héritage (d'un point de vue informatique) n'existe pas... même si les apparences ici nous y font penser.

Il est cependant vrai que l'élargissement d'une empreinte d'un prototype à l'autre peut y faire croire... mais oubliez-le.

Java est un langage rigoureux qui se compile et qui doit donc être parfait pour sa version compilée qui sera exécutée... il exige entre autres de définir des types de variables, les classes, etc.
Au contraire, JavaScript est un langage très libre par rapport à Java. On ne doit pas déclarer toutes les variables, classes et méthodes en JavaScript. Il s'interprète au moment de son exécution chez le client et travaillera tant que ce qu'on lui demande de faire est réalisable. Les variables, paramètres et valeurs de renvoi n'ont pas besoin d'être typés explicitement.

Ceci explique qu'il s'arrête d'exécuter la suite à la ligne sf.meDevoir(150); et c'est pourquoi nous avons noté en commentaire la ligne précédente //document.write("<br>ici"); qui, si on supprime le commentaire, s'exécutera... ou sera la dernière instruction exécutée si on supprime le commentaire.

Un long message à lire et à comprendre, mais pas indispensable pour pouvoir utiliser le JS. À vous de tester ce code maintenant.

 

Exemple

<HTML>
<HEAD>
<TITLE>250a - objets methodes</TITLE>
</HEAD>

<BODY>
<h1>objets et methodes</h1>
<script type="text/javascript">
//constructeur de l'empreinte o_Personne
function o_Personne(p_n,p_pr) {
   this.nom = p_n;
   this.prenom = p_pr;
}
//1re méthode sur des personnes avant instanciation
o_Personne.prototype.donner1Nom = function () {
   return this.nom;
};

//instanciation
var fd = new o_Personne("Del","Fred");
var sf = new o_Personne("Far","Sih");
//1re utilisation
document.write("essai 1 : "+fd.donner1Nom());
//2e méthode sur des personnes après instanciation
o_Personne.prototype.direSonNom = function () {
   return "Salut, mon nom est : " + this.donner1Nom();
};

//2e utilisation
document.write("<br>essai 2 : "+fd.direSonNom());
//3e utilisation de cette méthode sur sf
document.write("<br>essai 3 : "+sf.direSonNom());
//constructeur de l'empreinte o_Etudiant (semblable à o_Personne)
function o_Etudiant(p_n,p_pr) {
   this.nom = p_n;
   this.prenom = p_pr;
}
//et comme mes étudiants sont des personnes déjà définies
o_Etudiant.prototype = new o_Personne();
//instanciation d'un étudiant... qui sera une personne
var gp = new o_Etudiant("Pal","Gio");
//4e utilisation d'une méthode définie pour personnes sur l'étudiant gp
document.write("<br>essai 4 : "+gp.direSonNom());

/* toute nouvelle méthode attribuée à o_Personne sera applicable à o_Etudiant
mais le contraire ne sera pas vrai */
//attribuons une nouvelle méthode à o_Etudiant

o_Etudiant.prototype.meDevoir = function(du) {
   this.montantdu = du;
}
o_Etudiant.prototype.meDevra = function() {
   var duFutur = 1.1*this.montantdu;
   return duFutur;
}

//attribuons un montant du à un o_Etudiant non déclaré dans les o_Personne
gp.meDevoir(200);
//affichons ce qu'il me devra
document.write("<br>essai 5 : "+gp.prenom+" "+gp.nom+" me devra en fin d'année : "+gp.meDevra()+" euros.");

//attribuons un montant du à un o_Personne non déclaré dans les o_Etudiant
//document.write("<br>ici");
sf.meDevoir(150);
//affichons ce qu'il me devra
document.write("<br>essai 6 : "+sf.prenom+" "+sf.nom+" me devra en fin d'année : "+sf.meDevra()+" euros.");

</script>

</BODY>
</HTML>


 

 

E. méthode avec ou sans paramètre(s) ???

Le lecteur attentif aura peut-être observer en lisant ce qui précède que nous avons introduit des méthodes sans paramètre :

Malheureusement, là, c'est moi qui avais raison et vous qui avez tort, car meDevoir() ne fait rien d'autre qu'ajouter une nouvelle propriété à l'objet o_Etudiant... on ne peut donc pas parler de méthode.

Par contre, là où j'avais probablement tort, c'est que je ne vous ai montré aucune méthode avec un (ou plusieurs) paramètre(s). Je m'empresse donc de corriger cette imprécision.

 

F. un exemple de méthode avec paramètre(s)... et introduction aux tableaux

Le lecteur se rappellera (ou relira) le point B. ci-dessus. Il s'agissait de créer un objet eleve, puis de définir deux méthodes propres à eleve, toutes deux définies par le constructeur d'objet.

Notre but ici, sera de lui affecter une autre méthodes qui permettrait d'ajouter des amis de l'élève en question. Encore faudrait-il que eleve soit un objet qui ait une propriété amis. De plus, comme un eleve peut n'avoir aucun ami ou en avoir plusieurs, la propriété amis sera un tableau (ou array) [ce sujet sera approfondi dès le chapitre suivant : 26], mais nous en exposerons l'essentiel ici.

Si le tableau amis est vide, on notera [],
s'il contient un ami, on le notera entre les crochets,
et s'il contient plusieurs amis, on séparera chaque donnée du tableau entre crochets par une virgule.

Nous devrons donc modifier notre constructeur de la manière suivante (les nouveautés sont notées en mauve) :

function eleve(id,n,pren,dN,sx,cl,friends) {
    this.id = id;
    this.nom = n;
    this.pren = prenom;
    this.dateNaissance = dN;
    this.sexe = sx;
    this.classe = cl;
    this.amis = friends;
    this.afficherAge = function() {
        var aujourdhui = new Date();
        var an_aujourdhui = aujourdhui.getFullYear();

        var age = an_aujourdhui - dN;
        document.write("Il y a " + age + " que "+ this.nom + " est entré dans ce bas monde");
    }
    this.afficherInfos = function () {
        alert(this.eleve.prenom + " " + this.eleve.nom + " de sexe "+ this sexe +
             " a comme identificateur " + this.id +"./n");
    }
}

Et, après que le constructeur soit valablement établi, pour instancier quelques élèves, je devrais écrire :

var fredel3rse = new eleve("fredel3rse","Delgrange","Frédérique","14/02/1990","f","3rse",[]);
var giopall3rse = new eleve("giopal3rse","Palograno","Giovanino","04/12/1990","m","3rse",[]);
var katnou3rse = new eleve("katnou3rse","Nouskovitch","Katarina","23/09/1990","f","3rse",[]);
 

Rien de bien nouveau, sauf que le lecteur attentif constatera qu'aucun élève de la classe n'a d'amis... et c'est pourtant logique, puisque notre but est de créer une méthode permettant d'ajouter des amis.

 

1. ajout d'amis sans méthode

Si la curiosité vous a poussé à en savoir plus sur les tableaux, vous aurez probablement découvert qu'il existe une méthode push qui est destinée à ajouter des éléments à un tableau (voir chap. 29 méthodes pour les tableaux).

Nous pourrions l'utiliser ainsi, si nous voulons ajouter un ami dans la listes des amis de fredel3rse :

    fredel3rse.amis.push(new eleve("sihfar3rse","Farmidable","Sihot","18/01/1991","m","3rse",[])); 

Et, puisque l'on peut ajouter ainsi un ami dans le tableau (la collection) des amis, on peut généraliser la méthode en la plaçant dans le constructeur de la fonction eleve. Pour cela, on complètera le constructeur ci-dessus en lui ajoutant la méthode ajouterAmi() [voir la modification en rouge].

 

2. ajout d'amis par méthode définie dans le constructeur

Tout a été dit, il ne reste plus qu'à le faire :

function eleve(id,n,pren,dN,sx,cl,friends) {
    this.id = id;
    this.nom = n;
    this.pren = prenom;
    this.dateNaissance = dN;
    this.sexe = sx;
    this.classe = cl;
    this.amis = friends;
    this.afficherAge = function() {
        var aujourdhui = new Date();
        var an_aujourdhui = aujourdhui.getFullYear();

        var age = an_aujourdhui - dN;
        document.write("Il y a " + age + " que "+ this.nom + " est entré dans ce bas monde");
    }
    this.afficherInfos = function () {
        alert(this.eleve.prenom + " " + this.eleve.nom + " de sexe "+ this sexe +
             " a comme identificateur " + this.id +"./n");
    }
    this.ajouterAmi = function (ident,name,firstn,dateN,sex,classe,frnds) {
        this.amis.push(new eleve(ident,name,firstn,dateN,sex,classe,frnds));
    }

}

Et, pour ajouter le même ami Sihot Farmidable à notre élève Frédérique Delgrange, il me suffira d'écrire :

    fredel3rse.ajouterAmi("sihfar3rse","Farmidable","Sihot","18/01/1991","m","3rse",[])); 

et la méthode reste disponible pour l'ajout d'autres amis.

 

3. ajout d'amis par méthode définie dans le prototype

Et, puisque je vous ai parlé de méthode définie par le prototype d'un objet, je m'en voudrais de ne pas illuster à nouveau ce propos.

Dès que l'on crée un nouvel objet, JS lui attribue un sous-objet (ou une propriété intrinsèque) prototype. Cet objet prototype nous a déjà permis d'ajouter des propriétés à un objet que nous définissons (voir fin de la séquence 24.3 Ajout de propriétés à ses propres objets), il va maintenant nous permettre d'ajouter des méthodes à un objet que nous définissons. Comment ? Il suffit de le construire ainsi :

 eleve.prototype.ajouterAmi = function(ident,name,firstn,dateN,sex,classe,frnds){
     this.amis.push(new eleve(ident,name,firstn,dateN,sex,classe,frnds));
}

Ici aussi, pour ajouter le même ami Sihot Farmidable à notre élève Frédérique Delgrange, il me suffira d'écrire :

    fredel3rse.ajouterAmi("sihfar3rse","Farmidable","Sihot","18/01/1991","m","3rse",[])); 

et la méthode reste également disponible pour l'ajout d'autres amis.

Alors, convaincu maintenant que l'on peut ajouter des méthodes à ses objets en leur passant un ou plusieurs paramères ?

 

 

II. Attribution de méthode hors constructeur

voir suite >>>

 

 

VIII. Exercices relatifs aux méthodes applicables aux objets propres

voir suite >>>

 

IX. Test relatif aux méthodes applicables aux objets propres

voir suite >>>

 

 


test relatif aux objets propres et leurs propriétés(24.9) | | Attribution de méthodes hors constructeur (25.2)