Les objets en JavaScript
#1
Qu'est ce qu'un objet ?
On va prendre un exemple concret. Supposons que l'on veuille gérer une boutique en ligne d'articles de sport. Tous les articles vont avoir des caractéristiques communes. Ils vont tous avoir un nom de produit, ils vont tous avoir une référence et aussi un prix hors taxes. Ils auront aussi une fonctionnalité commune car pour tous les articles on aura besoin de calculer le prix toutes taxes comprises.
- Au niveau du code que l'on va écrire pour gérer cette boutique on voit bien que pour chaque article on va avoir besoin d'une variable
produit
pour stocker le nom du produit, d'une autre variablereference
pour stocker la référence et d'une dernière variableprixHT
pour stocker le prix hors taxes. - Ces variables sont liées entre elles car elles correspondent à un article. Et ces variables ont une valeur spécifique pour chacun de ces articles.
- La première idée c'est de regrouper ces variables et de les encapsuler dans une "boîte". Cette boite on va lui donner un nom et pour ça on va se servir d'une variable. On va l'appeler
article1
. Déjà je peux le dire cette boîte c'est un objet. Ci-dessous je vous montre sur un schéma ce que sera l'objetarticle1
utilisé pour un "Sac à dos".Un premier objet article1 - Si maintenant je veux fabriquer un objet pour des "Skis de rando" et bien je vais avoir besoin d'une deuxième boîte. Cette fois je vais utiliser la variable
article2
et je vais refaire la même chose cet à dire avoir besoin dans la boite d'une variable pour le nom du produit, d'une autre pour la référence... Ci-dessous je vous montre avec un schéma ce que sera l'objetarticle2
.Un deuxième objet article2 - Deux remarques :
- Vous imaginez facilement que si on fabriquait un objet pour une boutique réelle il aurait beaucoup plus variables car il y aurait beaucoup plus de caractéristiques.
- Et je peux ajouter que pour une boutique réelle on aurait probablement besoin de beaucoup d'articles.
Du coup la deuxième idée va être de fabriquer une "boîte modèle" et de l'utiliser pour construire chacun de nos articles.
Dans notre exemple cette "boîte modèle" on va l'appeler
Article
. Vous voyez sur le schéma ci-dessous que les variables dans cette "boîte modèle" ne sont pas initialisées. Cette boîte doit aussi contenir la fonctioncalculerPrixTTC
.Un modèle pour construire nos objets Etant donné que l'on se sert de cette "boîte modèle" pour construire les objets. Cette "boîte modèle" on l'a appelé le constructeur. Et maintenant on ne va plus parler de "boîte modèle" mais on va parler de constructeur.
Maintenant avant de partir tête baissée dans le code on va regarder ce que doit faire un constructeur pour construire un nouvel objet par exemple
article3
. Pour ce nouvel objet il va allouer de la mémoire puis il va regarder la liste des variables qu'on lui donné et dans cette mémoire il va implanter la même liste de variables. Ensuite il faudra qu'il initialise chacune de ces variables avec la valeur spécifique à ce nouvel objet. - Au niveau vocabulaire: les variables
produit
,reference
,prixHT
s'appellent les propriétés d'un objet et la fonctioncalculerPrixTTC
s'appelle une méthode d'un objet. Ici il n'y a qu'une seule méthode mais bien sûr il pourrait y en avoir plusieurs. - Pour mettre en oeuvre notre constructeur en JavaScript on a plusieurs solutions. On peut utiliser une classe ou une fonction constructeur et dans la suite du tuto on va poursuivre l'exemple en utilisant une classe.
#2
Un point de vocabulaire pour ne pas s'embrouiller
Alors pourquoi pourrait-on s'embrouiller ? Et bien parce que l'on peut dire les mêmes choses de plusieurs façons différentes.
- De manière générale on construit les objets avec un constructeur. C'est ce qu'il faut retenir.
- Si on utilise une classe pour le constructeur le plus souvent on dit que l'on instancie la classe. A ce moment là on parle d'instance au lieu de parler d'objet. Mais une instance et un objet c'est strictement la même chose. C'est juste une autre façon de le dire.
- Si on utilise une fonction constructeur il m'est arrivé de lire que l'on instancie un nouvel objet à partir la fonction constructeur. C'est même une expression que j'ai trouvé dans la doc MDN.
Ne vous laissez pas embrouiller. Instancier moi je le traduis par "prendre un exemplaire". Par exemple lorsque l'on dit que l'on prend une instance d'une classe on peut dire que l'on prend un exemplaire de la classe. Lorsque on dit que l'on instancie un nouvel objet à partir d'une fonction constructeur on peut dire que l'on prend un nouvel exemplaire d'un objet à partir d'une fonction constructeur. Ce qui est important c'est de ne pas perdre de vue qu'il y a d'un côté le constructeur et de l'autre les objets.

#3
La déclaration d'une classe et la construction des objets
Maintenant je vais coder le constructeur. Je vais le faire en utilisant les classes JavaScript qui sont disponibles depuis la version ECMAScript 6 soit l'édition de 2015.
Je vais prendre Sublime Text et créer sur le bureau un fichier que je vais appeler Article.html
. Je fais !>script
puis tab
et je donne le titre Article
à la page web.
Maintenant, je fais Open in Browser
dans Sublime de manière à avoir sous les yeux le code et son exécution.
- Qu'est ce que j'ai fait dans le code ci-dessus ? En premier j'ai déclaré la classe
Article
.Donc ça c'est le constructeur. Comprenez bien que c'est une déclaration. C'est comme une déclaration d'une grosse fonction. Ensuite j'ai appelé la fonction en faisant lenew Article()
. J'ai construit un premier objetarticle1
en utilisant les valeurs spécifiques àarticle1
(* 'Sac à dos'...). Ensuite j'ai construit un deuxième objetarticle2
en instanciant une nouvelle fois la classe mais cette fois ci en utilisant les valeurs spécifiques àarticle2
(* 'Ski de rando'...). - Pour déclarer la classe
Article
, je dois utiliser le mot réservéclass
et le faire suivre deArticle
. L'usage veut que l'on mette une majuscule àArticle
qui signale que c'est un nom de classe. En fait cet usage vient des fonctions constructeurs. La majuscule permettant dans ce cas de différencier une fonction constructeur d'une fonction normale. On a gardé cet usage avec les classes. - Ensuite j'ai déclaré une fonction qui doit s'appeler
constructor
(constructeur en français). Donc dans la classe il y a une fonction qui va faire ce travail de construction et c'est celle là. Notez que je n'ai pas eu besoin d'utiliser le mot réservéfunction
. - Cette fonction
constructor
est appelée au moment dunew Article()
. C'est le moteur JavaScript qui l'appelle ce n'est pas le programmeur. Le programmeur déclenche l'appel deconstructor
il ne l'appelle pas directement. Et c'est les arguments qui sont passés ici àArticle()
qui vont être passés à la fonctionconstructor
. - La fonction
constructor
va allouer l'objet en mémoire. Le mot réservéthis
est un pointeur qui va pointer sur la zone mémoire allouée pour ce nouvel objet. Unconsole.log
detypeof this
afficheobject
qui est du type pointeur sur un objet. Et unconsole.log
dethis
affiche l'objet qui est en cours de construction. On peut remarquer que leconsole.log
prend un pointeur en argument et qu'il affiche l'objet pointé et non le pointeur. Pour ceux qui on fait du langage C ici leconsole.log
déréférence le pointeur. - La fonction
constructor
va initialiser les propriétés du nouvel l'objet avec les valeurs spécifiques du nouvel l'objet. C'est ce qui se fait par exemple ici pour la propriété produitthis.produit = produit
. Pour pouvoir faire ça il faut que les valeurs du nouvel objet soient en paramètre de la fonctionconstructor
. Je vais avoir besoin d'une valeur pour chaque propriété à initialiser, donc d'un paramètre pour chaque propriété. Et en général on donne le même nom au paramètre et à la propriété. - Notez bien que les variables
article1
etarticle2
reçoivent chacune la valeur d'un pointeur. C'est une valeur retournée par lenew Article()
. La valeur duthis
. C'est comme ça que les variablesarticle1
etarticle2
récupère l'adresse de l'objet en mémoire. - On peut le vérifier avec la console. Je fais un
typeof article1
et je lisobject
. Doncarticle1
est du type pointeur sur objet. - Maintenant je tape
article1
, je déploie, je peux visualiser les trois propriétésproduit
reference
etprixHT
.

Tout ça c'est bien mais où est passé la méthode calculerPrixTTC
? Alors la réponse je vais la donner dans le chapitre ci-dessous.
#4
Qu'est-ce qu'un prototype ?
- Je clique sur la propriété
__proto__
et je vois apparaître la méthodecalculerPrixTTC()
. - Maintenant je tape
article2
puis je déploieArticle
puis__proto__
et ici aussi je vois apparaître la méthodecalculerPrixTTC()
. - A ce stade on pourrait croire que chaque objet a sa propre méthode. Heureusement ce n'est pas le cas. Imaginez qu'il y ait 1000 objets !! Ce serait idiot d'implanter 1000 fois la même méthode en mémoire.
- En fait la méthode a été placée dans ce que l'on appelle un prototype. Il s'agit d'un objet au sens JavaScript du terme c'est à dire qu'en interne le prototype est implémenté par un objet. Dans notre exemple c'est le prototype de tous les objets de la classe
Article
. Il y en a qu'un seul et on va le vérifier.article1
etarticle2
partagent le prototype des objets de la classeArticle
- Faites
typeof article1.__proto__
et vous obtenezobject
. - Faites
typeof article2.__proto__
et vous obtenezobject
. - Et si maintenant vous testez l'égalité de ces deux
__proto__
et bien vous voyez qu'ils sont égaux c'est à dire qu'ils pointent sur le même objet.Les deux pointeurs __proto__
des objets sont égaux
Donc tous les objets construits avec la classe Article
vont partager ce prototype et il faut remarquer que c'est de cette manière qu'ils vont partager le code de la méthode. Le code de la méthode n'est pas dupliqué.
Cependant si vous regardez dans le premier __proto__
vous constatez qu'il contient un autre __proto__
qui lui pointe sur le prototype d'un Object
. Ensuite ça s'arrête. J'ai mis un point d'interrogation sur le schéma car on va voir à quoi ça correspond dans la suite du tuto.
#5
Comment se servir d'une classe parent pour créer une classe enfant
Il y a une deuxième façon d'utiliser la "boîte modèle". Pour créer une nouvelle classe plutôt que de partir d'une boîte vide on va récupérer une classe qui existe déjà. Dans la nouvelle classe on va juste écrire les propriétés et les méthodes que l'on ajoute. La nouvelle classe est appelée classe enfant ou classe dérivée et la classe récupérée est appelée la classe parent. Ce mécanisme qui permet de récupérer des propriétés et des méthodes existantes s'appelle l'héritage en Programmation Orientée Objet (POO).
Il faut bien comprendre que les objets enfants que l'on construira auront les propriétés et méthodes spécifiques à la classe enfant PLUS les propriétés et méthodes de la classe parent. C'est à dire les propriétés et méthodes que la classe enfant hérite de la classe parent.

Poursuivons notre exemple. Supposons que l'on veuille mettre des articles en promotion dans notre boutique en ligne. Ces articles ont les mêmes caractéristiques que les autres articles à savoir qu'ils ont toujours un nom de produit, une référence et un prixHT. Mais en plus ils ont une propriété supplémentaire qui est la remise que l'on va faire sur le PrixTTC. Et aussi une méthode en plus pour calculer le prix de vente en promotion.
Nous ce qu'on veut c'est pas tout recommencer, alors on va se servir de la classe Article
.
Etant donné que nous avons à notre disposition en JavaScript un mécanisme d'héritage on va récupérer la classe Article
pour construire une nouvelle classe Promo
. Et pour Promo
on va se contenter d'ajouter une propriété remise
et une méthode calculerPrixPromo()
.
Promo
à partir de la classe Article

Je vais sauvegarder le fichier Article.html
sous un nouveau nom Promo.html
. Je vais travailler maintenant sur Promo.html
.
- Je déclare la classe
Promo
comme une extension de la classeArticle
. Je dois utiliser le mot réservéextends
. - Maintenant je dois déclarer un constructeur pour la classe
Promo
. Ce constructeur doit prendre comme paramètres de déclaration l'ensemble des propriétés des deux classes puisque les propriétés des deux classes doivent être affectées au moment de l'instanciation. Les propriétésproduit
,reference
etprixHT
de la classe parent et la propriétéremise
de la classe dérivée. - Dans ce constructeur, je dois appeler le constructeur de la classe parent en utilisant le mot réservé
super
. Et je passe les paramètres de déclaration du parent. - Ensuite je dois initialiser la propriété de la classe enfant. Ici il n'y a que
remise
. J'utilise à nouveauthis
qui pointe ici toujours sur un nouvel objet mais cette fois ci un objet de la classePromo
. - Ensuite je passe au codage de la méthode
calculerPrixPromo
. Pour cela j'ai besoin d'accéder à la méthodecalculerPrixTTC
de la classe parent et pour y accéder je dois à nouveau utiliser le mot réservésuper
. Mais cette fois ci je dois utiliser la notation pointée. - Ensuite je peux instancier
Promo
en prenant bien soin de mettre tous les paramètres d'appel.
#6
Héritage par prototype
- Reprenez le fichier
Promo.html
, avec la console examinez l'objetpromo
. - Vous constatez que le prototype de
Promo
semble "contenir" celui d'Article
. En fait c'est le pointeur__proto__
du prototype depromo
qui pointe vers celui d'Article
.
Promo

Ca veut dire qu'un prototype contient un pointeur vers un autre prototype. On a donc une liste chaînée de prototypes qui se termine par le prototype de l'objet Object
.

Pour le vérifier on va prendre l'objet promo
et on va aller sur son prototype puis on va descendre sur sa propriété __proto__
. On va comparer cette valeur à celle de article1.__proto__
. On va constater que les valeurs sont égales ce qui prouve le chaînage des prototypes.

Je résume le fonctionnement qui est très simple : si une propriété est demandée, l'interpréteur regarde d'abord dans l'objet. Si elle n'est pas dans l'objet il la cherche dans le prototype de l'objet. Si elle n'y est pas il remonte au prototype du parent et ainsi de suite jusqu'au prototype de Object
. Le prototype de Object
est le prototype de l'objet qui est en haut de la hiérarchie.
#7
Comment créer un objet littéral ?
C'est une autre façon de procéder pour créer un objet. Dans ce cas, le plus souvent, on commence par créer un objet vide en utilisant les accolades. Puis on ajoute ou on supprime des propriétés de manière dynamique. JavaScript a cette capacité de nous permettre d'ajouter ou de supprimer des propriétés au fur et à mesure de notre besoin.
Pour ajouter une propriété il suffit d'affecter une nouvelle propriété.
Pour supprimer une propriété il faut utiliser l'opérateur delete
.
- Avec Sublime faites
CTRL+N
pour créer un nouveau fichier puisCTRL+S
pour le sauvegarder sur le bureau. Vous lui donnez le nom deLitteral.html
. Faites!>script
puistab
. Donnez le titreLitteral
à la page web. - Déclarez un objet vide
article
en utilisant les accolades. - Ajoutez la propriété
produit
en affectantarticle.produit
à'Sac à dos'
. - Ajoutez la propriété
reference
en affectantarticle.reference
à645020
. - Ajouter la propriété
prixHT
en affectantarticle.prixHT
à35
. - Ajouter la propriété
stock
en affectantarticle.stock
à10
. - Supprimez la propriété
reference
avec undelete
surarticle.reference
. - Faites un
console.log()
pour afficher l'objet. - Faites un clic droit dans Sublime puis choisissez
Open in Browser
. PuisCTRL+SHIFT+I
pour accéder à la console. - Vérifiez la liste des propriétés.
Vous pouvez aussi utiliser la syntaxe JSON pour créer un objet avec ses propriétés initialisées. Chaque propriété est composée d'un couple nom et valeur. Le nom et la valeur sont séparés par le caractère deux points. Chaque couple nom et valeur est séparé par une virgule.
- Effacez ce qu'il y a dans l'élément
script
deLitteral.html
sauf leconsole.log()
. - Déclarez un objet en utilisant la syntaxe JSON.
- Faites un clic droit dans Sublime puis choisissez
Open in Browser
. PuisCTRL+SHIFT+I
pour accéder à la console. - Vérifiez la liste des propriétés.
#8
Tester si une propriété existe dans un objet
On peut se poser deux questions :
- Est ce que la propriété existe que ce soit dans l'objet ou dans sa chaîne de prototype ? C'est l'opérateur
in
qui répond à cette question. Il vous renvoietrue
si la réponse à la question est affirmative. - Est ce que la propriété existe dans l'objet ? C'est la méthode
hasOwnProperty()
qui répond à cette question. Elle renvoietrue
si la propriété se trouve dans l'objet. Elle renvoiefalse
si la propriété se trouve dans la chaîne de prototype, y compris le prototype de l'objet lui même.
On va tester ces deux moyens d'abord sur la propriété remise
et sur la méthode calculerPrixPromo()
qui appartiennent à l'objet Promo
, puis sur la propriété valueOf
qui elle appartient à Object
.
#9
Parcourir la liste des propriétés
#10
Passer un objet en paramètre d'appel d'une fonction
Reprenez le fichier Article.html
.
On a vu que article1
est un pointeur. Vous allez passer ce pointeur à une fonction. Le pointeur va être passé par copie comme expliqué dans le tuto sur les fonctions. Mais ce pointeur permettra un accès à l'objet et permettra une modification des propriétés de l'objet depuis la fonction.
Bien sûr article1
est globale et on peut y accéder dans la fonction modifier
mais ce n'est pas ce que je veux montrer.
