Développer efficacement en objet
Première approche
1. Rappels
Avant d’aborder concrètement le développement objet en JavaScript, nous allons effectuer quelques rappels sur ce mode de développement. En premier lieu, il faut bien comprendre que ce type de développement a été construit dans le but d’améliorer la qualité du développement en distinguant plusieurs niveaux de conception. Le premier niveau étant d’établir un plan de fabrication et le dernier niveau permettant d’obtenir un assemblage objets rendant le service voulu. D’autre part, des méthodes d’analyse et conception ont tenté de suivre ce modèle afin d’assurer une transition de développement plus souple partant de la modélisation du réel vers l’étape de fabrication.
a. Classe
Un objet est généralement construit à partir d’une classe. Cette classe joue le rôle d’usine à objets. Elle possède un plan de fabrication et peut fournir des objets à la demande.
Dans les plans de fabrication, nous avons des propriétés (ou attributs) qui stockent des informations propres à chaque objet et des méthodes qui permettent d’interagir avec ces objets.
Une propriété est en réalité une variable dont le contexte d’usage se limite à un objet en particulier. Elle n’existe en quelque sorte qu’à l’intérieur de l’objet, ce qui confère donc à ce dernier un état.
Une méthode d’un objet est aussi une fonction JavaScript mais qui n’existe que dans le contexte de cet objet et ayant un accès aux propriétés de l’objet (donc influant sur l’état de l’objet).
Si nous effectuons une analogie avec les objets de notre entourage, nous pouvons prendre l’exemple d’un téléphone mobile. Ces propriétés sont constituées de son paramétrage et des informations que nous y avons stockées, on constate bien qu’elles sont liées à un appareil uniquement. Les méthodes sont l’ensemble des actions disponibles sur le mobile, comme l’allumer, régler le volume, passer un appel. Si elles sont présentes pour tous les appareils...
Contexte d’exécution
1. this
En JavaScript, this ne désigne pas l’objet issu de l’instance uniquement, mais en réalité il désigne l’objet qui est en train d’être utilisé. Cela signifie que l’interpréteur JavaScript évalue this lors de l’appel d’une méthode, c’est un argument supplémentaire ajouté automatiquement.
Autrement dit, lorsque vous faites référence à this, vous n’êtes jamais certain que cela va concerner la bonne instance. Cette particularité est assez déroutante pour un développeur objet « classique » mais en réalité offre une grande puissance comme nous allons le voir.
Exemple
function Personne( nom, prenom ) {
this.nom = nom;
this.prenom = prenom;
this.bonjour = function() {
alert( "bonjour " + this.prenom );
};
}
function Chien( prenom ) {
this.prenom = prenom;
}
const p = new Personne( "brillant", "alexandre" );
const c = new Chien( "tobby" );
c.bonjour = p.bonjour;
c.bonjour();
Dans l’exemple, nous avons deux classes : Personne et Chien. Ces classes n’ont aucune relation entre elles à la base. Nous associons à la classe Chien la méthode bonjour provenant de la classe Personne, puis nous exécutons cette méthode au travers d’une instance. Nous obtenons alors le message « bonjour tobby ».
this représente l’instance sur laquelle est réalisé un appel de méthode.
Cela peut se traduire ainsi : monInstance.maMethode( ... )
En réalité, le comportement interne est traduit de cette manière :
this = monInstance
maMethode( this, ... )
Maintenant, imaginons que nous ayons à passer une référence vers une fonction de notre objet. Pour rappel, JavaScript est un langage qui à la base a été conçu pour fonctionner en relation avec une page HTML. Dans une page HTML, nous avons toutes sortes d’événements qui seront liés...
Classes prédéfinies
Nous allons maintenant présenter quelques classes d’usage courant. L’objectif n’est pas de présenter de manière exhaustive les propriétés et les méthodes de chaque classe mais de se concentrer sur les plus utiles. Pour obtenir une vue plus complète, vous pouvez vous référer aux liens présents en fin d’ouvrage.
1. Object
Tous les objets créés en JavaScript partagent les propriétés et les méthodes de la classe Object.
La principale propriété est prototype que nous analyserons par la suite et qui a l’avantage de donner accès à des propriétés et à des méthodes présentes de manière unique dans toutes les instances.
Exemple
function Personne( nom, prenom ) {
this.nom = nom;
this.prenom = prenom;
}
const p1 = new Personne( "brillant", "alexandre" );
const p2 = new Personne( "jean", "dupont" );
Personne.prototype.bonjour = function() {
alert( "bonjour " + this.prenom );
};
p1.bonjour();
p2.bonjour();
Dans cet exemple, nous ajoutons une méthode bonjour à la classe Personne que nous partageons avec toutes les instances. Preuve en est que nous l’avons ajoutée après la création des objets et qu’elle est pourtant disponible avec p1 et p2.
La méthode toString est également présente dans la classe Object qui est la classe parente par défaut pour donner une forme plus lisible de l’objet.
Exemple
function Personne( nom, prenom ) {
this.nom = nom;
this.prenom = prenom;
}
const p3 = new Personne( "brillant", "alexandre" );
alert( p3 ) ;
Nous obtenons le résultat [object object] peu agréable signifiant simplement que notre objet est lui-même composé de deux objets (les chaînes de caractères nom et prenom).
La méthode alert utilise en réalité la méthode toString, présente par défaut dans la classe Object. Pour améliorer l’affichage, nous allons étendre...
Classes
1. Création
a. Constructeur
Depuis la norme ECMAScript 6 (ES6) et afin d’éviter la confusion entre « fonction constructeur » et « fonction classique », JavaScript a introduit le concept de constructeur comme on peut l’avoir dans d’autres langages. Cela signifie qu’une classe aussi est représentable par le mot-clé class. Le mot-clé constructor est ensuite utilisé à l’intérieur.
Voici un exemple avec une classe « Poisson » :
class Poisson {
constructor(espece,couleur) {
this.espece = espece;
this.couleur = couleur;
}
getEspece() {
return this.espece;
}
getCouleur() {
return this.couleur;
}
}
const poisson = new Poisson( "poisson chat", "noire" );
alert( `Notre ${poisson.getEspece()} est de couleur
${poisson.getCouleur()}` );
Par convention, nous avons mis un nom de classe en commençant par une majuscule. Également, les méthodes de classes commencent par une minuscule. Il n’est pas utile de déclarer les attributs/propriétés de classe, cela est défini à l’usage dès que l’instruction this.attribut = value est utilisée et notamment dans le constructeur.
Nous avons défini deux attributs espece et couleur dans le constructeur. Pour effectuer la lecture de ces attributs, nous avons ajouté les méthodes getEspece et getCouleur. Le fait de commencer par « get » est une convention assez courante pour indiquer une opération de lecture, de même que pour une opération d’écriture, nous aurons une méthode commençant par « set ».
La création d’une instance passe toujours par l’opérateur new avec les paramètres du constructeur. Nous affichons ensuite les informations sur notre objet par les getters (raccourci pour...