JavaScript n'utilise pas la notion de classe pour la création d'objets . A la place les objets peuvent être crées par différentes manières notamment par constructeur qui crée l objet et initialise certain propriétés .
Le constructeur est une fonction qui possède une propriété
"prototype" utilisée pour l héritage basé sur le prototype et pour partager les propriétés entre différentes instances . Les instances d'objets sont alors créées par le mot clef
"new" suivi du constructeur ex :
new String(
"bonjour").Ainsi chaque instance partage une référence avec le prototype de son constructeur .
Voyons maintenant pour examiner quelques exemples de création d'objet en JavaScript . On utilisera la classe "personne" pour questions pratiques.
Création par constructeur
on déclare une fonction dans laquelle on implémente les méthodes et propriétés ce qui rappel les classes dans d'autres langages orientes objet tels que C++, Java, C#...
function Personne( nom, sexe){
this.DateNaissance=new Date();
this.nom=nom || "Dupont";
this.sexe=sexe;
this.renommer=function(nom){
if(nom)this.nom=nom;
};
}
On a déclaré le constructeur , on ajoute quelques méthodes par le prototype ; methodes qui seront partagées par toutes les instances .
Personne.prototype.quelAge=function(){
var ms=new Date()-this.DateNaissance;
var ans=ms/1000/60*60*24/365.25;
return Math.floor(ans)+1+" an";
}
Maintenant pour créer une instance on procède ainsi :
var jaques=
new Personne("Jacques","Masculin");
//affiche l age de Jacques.
alert(jaques.quelAge());
ce qui affiche
1 an , normal Jacques vient de naître il a moins d'un an . on va pas dire zéro ...
Création par notation littérale
cette fois au lieu de passer par le constructeur on instancie directement un objet par une instance de l objet prédéfinie Object :
var jaques=
new Object();
//on attache dynamiquement les propriétés a l'instance
jaques.nom=
"Jacques";
jaques.sexe=
"Masculin";
jaques
.DateNaissance=new Date();
jaques
.quelAge=function(){
var ms=new Date()-this.DateNaissance;
var ans=ms/1000/60*60*24/365.25;
return Math.floor(ans)+1+" an";
}
alert(jaques.quelAge());
de même que précédemment affiche
1 an.
Une autre façon de créer un objet est d'utiliser la représentation JSON soit :
var jaques=
{};
//on attache dynamiquement les propriétés a l'instance
jaques.nom=
"Jacques";
jaques.sexe=
"Masculin";
jaques
.DateNaissance=new Date();
jaques
.quelAge=function(){
var ms=new Date()-this.DateNaissance;
var ans=ms/1000/60*60*24/365.25;
return Math.floor(ans)+1+" an";
};
alert(jaques.quelAge());
ce qui affiche
1 an.
ou directement :
var jaques=
{
//on attache dynamiquement les propriétés a l'instance
nom
:"Jacques",
sexe
: "Masculin",
DateNaissance : new Date(),
quelAge : function(){
var ms=new Date()-this.DateNaissance;
var ans=ms/1000/60*60*24/365.25;
return Math.floor(ans)+1+" an";
}
};
//et on ajoute une propriétés
jaques.
renommer=function(nom){
if(nom)this.nom=nom;
};
alert(jaques.quelAge());
Affiche a nouveau
1 an.
On vient de voir les Différentes manières de création d'objet et JavaScript a présent on s’intéressera au autre notions de la programmation oriente objet POO en JavaScript et on fera une analogie avec les autre langages objet
Variables et accesseurs
En utilisant la création par constructeur qui ressemble a la notion de classe dans Java, C# :
On peut distinguer différents accesseur pour les attributs d un objet
privé, public , public privilégie, et public statique
pour illustration reprenons l exemple de "Personne"
function Personne( nom, sexe){
//propriétés privées
var celibataire =true;
//propriétés public privilégiées
this.DateNaissance=new Date();
this.nom=nom|| "Dupont";
this.sexe=sexe;
//incrémentation d'une propriétés public statique
this.constructor.nombreDeNaissance++;
//méthodes public privilégiées
this.renommer=function(nom){
if(nom)this.nom=nom;
};
this.seMarie= function(){
celibataire =false;
};
this. estMarie=function(){
return celibataire?"Non":"Oui" ;
}
this.divorce = function(){
celibataire=true;
};
this.mange= function(){
alert("envoies la mayonnaise ");
};
this.quelAge= function(){
return calculerAge(this.DateNaissance);
};
//méthodes privées
function calculerAge(date){
var ms=new Date()-date;
var ans=ms/1000/60*60*24/365.25;
return Math.floor(ans)+1+" an";
};
}
//propriétés public statique
Personne.nombreDeNaissance=0;
//méthodes public
Personne.prototype.mange=function(){
alert("...pas faim !! ");
};
var jaques=
new Personne("Jacques","Masculin");
alert(jaques.quelAge()); //affiche 1 an
//utilise la méthode privée pour calculer l age
alert(jaques.estMarie()); //affiche Nom
//affiche la valeur de propriété privée celibataire
jaques.seMarie() ;
//modifie la valeur de propriété privée celibataire
alert(jaques.estMarie()); //affiche Oui
//affiche a nouveau la valeur de propriété privée celibataire
jaques.divorce () ;
//modifie la valeur de propriété privée celibataire
alert(jaques.estMarie()); //affiche Nom ,(il vient de divorcer)
//affiche a nouveau la valeur de propriété privée celibataire
alert(Personne.nombreDeNaissance); //affiche 1 (celle de Jacques)
//affiche la valeur de propriété statique nombreDeNaissance
jaques.mange() //affiche envoies la mayonnaise
/
//on constate que c est la méthode public privilégié qui s’exécute non la méthode public définie dans le prototype
Ici on ajoute a jacques des propriétés dynamiquement :
jaques.celibataire="depuis peu";
alert(jaques.estMarie()); //affiche Nom
//affiche toujours la valeur de propriété privée celibataire
var marie=
new Personne("Marie","féminin");
alert(jaques.celibataire);//affiche depuis peu
alert(marie
.celibataire); //affiche undefined
jaques possède deux propriétés qui portent le même nom "celibataire" une public et l autre privée .
par contre marie ne possède que la propriété privée du même nom celle du constructeur
Héritage , polymorphisme extension d'objet
allons droit au but et gardons en tète la "classe" Personne définie précédemment a la quelle on rajoutera quelles attributs soit :
Personne.prototype.toString=function (){
return "[Personne]:"+this.nom;
}
Personne.prototype.travailler=function (){
return "[Personne]: que c'est dur";
}
Maintenant on veut créer une classe Salarie qui dérive de Personne ?
On pourrait directement créer une instance de la Personne et on rajoute les propriétés spécifiques au salarié Mais dans notre cas on veut rester avec les constructeurs et prototype la première idée serait d écrire ce ci :
Salarie .prototype=new Personne();
//assigner toutes les propriétés d'une instance de
//personne au prototype de nouvelle instance Salarie
function Salarie (nom ,profession){
Personne.call(this,nom);
//on exécute le constructeur de la classe Personne dans le
// contexte de Salarie
this.salaire=1000;
this.profession=profession;
//propriétés spécifiques au Salarie
}
Voyons ce que ça donne en vrai :
var marie=new Salarie ("Marie","Comptable");
alert(marie );//appel toString affiche [Personne]:Marie
alert(marie.profession); //affiche Comptable
marie.mange() ;//affiche envoies la mayonnaise
alert(marie.travailler()); //"[Personne]: que c'est dur";
C'est déjà pas mal !. Mais si on veut faire en sort que la surcharge puisse fonctionner ? on le constate bien le
toString affiche toujours
[Personne]:Marie si on veut plutôt
[Salarie ]:Marie
dans ce cas faudra réexaminer le
toString de la classe de base ainsi :
Personne.prototype.toString=function (){
return "["+this.constructor.name+"]"+this.nom;
}
Personne.prototype.travailler=function (){
return "["+this.constructor.name+"]: que c'est dur";
}
et on précise a la classe Salarie que le constructeur associé a son prototype est bien Salarie
ce qui donne :
Salarie .prototype=new Personne();
Salarie.prototype.constructor=Salarie ;
//assigner toutes les propriétés d'une instance de
//personne au prototype de nouvelle instance Salarie
//associe Salarie au constructeur de son prototype
function Salarie (nom ,profession){
Personne.call(this,nom);
//on exécute le constructeur de la classe Personne dans le
// contexte de Salarie
this.salaire=1000;
this.profession=profession;
//propriétés spécifiques au Salarie
}
var marie=new Salarie ("Marie","Comptable");
alert(marie );//appel toString affiche [Salarie ]:Marie
alert(marie.profession); //affiche Comptable
alert(marie.travailler()); //"[Salarie ]: que c'est dur";
Et voilà ! ca fonctionne presque comme de l héritage classique . Bien sur c est pas encore parfait ;
on est obligé d 'écrire a chaque fois les appels a la classe de base de spécifier chaque fois les appels au prototype voyons comment automatiser tout ça :
En premier abord on est tenté de créer une fonction qui va faire appels précédents a notre place par exemple étendre l'objet
Function de Javascript ainsi que
Object cette fonction on va l inclure a chaque fois .
Exemple de fonction pour l héritage :
if
(
typeof
Function.prototype.extends != "
function"
){
Function.prototype.extends=function (base){
this.prototype = new base();
this.prototype.constructor = this;
}
}
if
(
typeof
Object.prototype.extends != "
function"
){
Object.prototype.extends=function (base){
(arguments.length>1)?
base.apply(this,Array.prototype.slice.call(arguments,1)):
base.call(this);
}
}
Salarie.extends(Personne);
function Salarie (nom ,profession){
this.extends(Personne,nom )
this.salaire=1000;
this.profession=profession;
}
var marie=new Salarie ("Marie","Comptable");
alert(marie );//appel toString affiche [Salarie ]:Marie
alert(marie.profession); //affiche Comptable
alert(marie.travailler()); //"[Salarie ]: que c'est dur";
Dire qu'on peut déjà s’arrêter là....
a suivre améliorations ....