Faire le quiz close

Les objets en JavaScript

#1 Qu'est-ce qu'un objet ? open

On va prendre un exemple. 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.

  1. 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 variable reference pour stocker la référence et d'une dernière variable prixHT pour stocker le prix hors taxes.
  2. 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.
  3. La première idée, c'est de regrouper ces variables et de les encapsuler dans une "boîte". Cette boîte, 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'objet article1 utilisé pour un "Sac à dos".
    Un premier objet article1
    Le schéma d'un premier objet article1
  4. Si maintenant, je veux fabriquer un objet pour des "Skis de rando" Eh 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, c'est-à-dire avoir besoin dans la boîte 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'objet article2.
    Un deuxième objet article2
    Le schéma d'un deuxième objet article2
  5. 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 fonction calculerPrixTTC.

    Un modèle pour construire nos objets
    Le schéma d'un modèle

    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.

    Un 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 a donnée, 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.

  6. Au niveau vocabulaire: les variables produit, reference, prixHT s'appellent les propriétés d'un objet et la fonction calculerPrixTTC 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.
  7. 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 open

Alors pourquoi pourrait-on s'embrouiller ? Eh bien, parce que l'on peut dire les mêmes choses de plusieurs façons différentes.

  1. De manière générale, on construit les objets avec un constructeur. C'est ce qu'il faut retenir.
  2. 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.
  3. 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. Lorsqu'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.

Un vocabulaire pas toujours évident
Un point de vocabulaire

#3 La déclaration d'une classe et la construction des objets open

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.

  1. 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 le new Article(). J'ai construit un premier objet article1 en utilisant les valeurs spécifiques à article1 (* 'Sac à dos'...). Ensuite, j'ai construit un deuxième objet article2 en instanciant une nouvelle fois la classe, mais cette fois-ci, en utilisant les valeurs spécifiques à article2 (* 'Ski de rando'...).
  2. Pour déclarer la classe Article, je dois utiliser le mot réservé class et le faire suivre de Article. 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.
  3. 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.
  4. Cette fonction constructor est appelée au moment du new Article(). C'est le moteur JavaScript qui l'appelle, ce n'est pas le programmeur. Le programmeur déclenche l'appel de constructor, il ne l'appelle pas directement. Et c'est, les arguments qui sont passés ici à Article() qui vont être passés à la fonction constructor.
  5. 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. Un console.log de typeof this affiche object qui est un pointeur sur un objet. Et un console.log de this affiche l'objet qui est en cours de construction. On peut remarquer que le console.log prend un pointeur en argument et qu'il affiche l'objet pointé et non le pointeur. Pour ceux qui ont fait du langage C, ici le console.log déréférence le pointeur.
  6. 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é produit this.produit = produit. Pour pouvoir faire ça, il faut que les valeurs du nouvel objet soient en paramètre de la fonction constructor. 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é.
    Initialisation de l'objet
  7. Notez bien que les variables article1 et article2 reçoivent chacune la valeur d'un pointeur. C'est une valeur retournée par le new Article(). La valeur du this. C'est comme ça que les variables article1 et article2 récupèrent l'adresse de l'objet en mémoire.
  8. On peut le vérifier avec la console. Je fais un typeof article1 et je lis object. Donc article1 est du type pointeur sur objet.
  9. Maintenant, je tape article1, je déploie, je peux visualiser les trois propriétés produit reference et prixHT.
Tester le code
Role du this

Tout ça, c'est bien, mais où est passée la méthode calculerPrixTTC ? Alors la réponse, je vais la donner dans le chapitre ci-dessous.

#4 Qu'est-ce qu'un prototype ? open

  1. Je clique sur la propriété __proto__ et je vois apparaître la méthode calculerPrixTTC().
    Examiner la propriété __proto__
  2. Maintenant, je tape article2, puis je déploie Article, puis __proto__ et ici aussi, je vois apparaître la méthode calculerPrixTTC().
    Où est la méthode calculerPrixTTC ?
  3. 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.
  4. 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 et article2 partagent le prototype des objets de la classe Article
    article1 et article2 partage le proto d'Article
  5. Faites typeof article1.__proto__ et vous obtenez object.
  6. Faites typeof article2.__proto__ et vous obtenez object.
  7. Et si maintenant, vous testez l'égalité de ces deux __proto__, eh 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
    égalité des __proto__ testée sur la console

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 ? open

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.

Construire une classe enfant à partir d'une classe parent
Construire une classe par héritage

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. Ils ont aussi une méthode en plus pour calculer le prix de vente en promotion.

Nous, ce qu'on veut, c'est ne 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().

Construire la classe Promo à partir de la classe Article
Construire Promo à partir de Article

Je vais sauvegarder le fichier Article.html sous un nouveau nom Promo.html. Je vais travailler maintenant sur Promo.html.

  1. Je déclare la classe Promo comme une extension de la classe Article. Je dois utiliser le mot réservé extends.
  2. 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és produit, reference et prixHT de la classe parent et la propriété remise de la classe dérivée.
  3. 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.
  4. Ensuite, je dois initialiser la propriété de la classe enfant. Ici, il n'y a que remise. J'utilise à nouveau this qui pointe ici toujours sur un nouvel objet, mais cette fois-ci un objet de la classe Promo.
  5. Ensuite, je passe au codage de la méthode calculerPrixPromo. Pour cela, j'ai besoin d'accéder à la méthode calculerPrixTTC 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.
  6. Ensuite, je peux instancier Promo en prenant bien soin de mettre tous les paramètres d'appel.
Tester le code

#6 Héritage par prototype open

  1. Reprenez le fichier Promo.html, avec la console examinez l'objet promo.
  2. Vous constatez que le prototype de Promo semble "contenir" celui d'Article. En fait, c'est le pointeur __proto__ du prototype de promo qui pointe vers celui d'Article.
le prototype de Promo
S'y retrouver dans les infos console

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.

Liste chaînée de prototypes
Liste chaînée de prototype

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.

Pointeurs en rouge sur le schéma ci-dessus
Preuve du 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 ? open

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.

  1. Avec Sublime, faites CTRL+N pour créer un nouveau fichier puis CTRL+S pour le sauvegarder sur le bureau. Vous lui donnez le nom de Litteral.html. Faites !>script puis tab. Donnez le titre Litteral à la page web.
  2. Déclarez un objet vide article en utilisant les accolades.
  3. Ajoutez la propriété produit en affectant article.produit à 'Sac à dos'.
  4. Ajoutez la propriété reference en affectant article.reference à 645020.
  5. Ajouter la propriété prixHT en affectant article.prixHT à 35.
  6. Ajouter la propriété stock en affectant article.stock à 10.
  7. Supprimez la propriété reference avec un delete sur article.reference.
  8. Faites un console.log() pour afficher l'objet.
  9. Faites un clic droit dans Sublime, puis choisissez Open in Browser. Puis, CTRL+SHIFT+I pour accéder à la console.
  10. Vérifiez la liste des propriétés.
Tester le code

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.

  1. Effacez ce qu'il y a dans l'élément script de Litteral.html sauf le console.log().
  2. Déclarez un objet en utilisant la syntaxe JSON.
  3. Faites un clic droit dans Sublime puis choisissez Open in Browser. Puis CTRL+SHIFT+I pour accéder à la console.
  4. Vérifiez la liste des propriétés.
Tester le code

#8 Tester si une propriété existe dans un objet open

On peut se poser deux questions :

  1. 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 renvoie true si la réponse à la question est affirmative.
  2. Est-ce que la propriété existe dans l'objet ? C'est la méthode hasOwnProperty() qui répond à cette question. Elle renvoie true si la propriété se trouve dans l'objet. Elle renvoie false 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.

Tester le code

#9 Parcourir la liste des propriétés open

Tester le code

#10 Passer un objet en paramètre d'appel d'une fonction open

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.

un pointeur en paramètre d'appel
Un pointeur en paramètre d'appel
Tester le code