IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JavaScript Discussion :

Question sur le cours de POO en javascript(1ère partie)


Sujet :

JavaScript

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Août 2004
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2004
    Messages : 32
    Par défaut Question sur le cours de POO en javascript(1ère partie)
    Bonjour,

    Je suis débutant en Javascript, mais il me semble qu'il y a une erreur sur le premier article sur la POO en javascript concernant l'accès au méthodes définies dans l'objet associé à la propriété prototype d'un constructeur. le cours est celui ayant pour titre Programmation orientée objet avec le langage Javascript (1ère partie) de Thierry Templier et le code concerné est celui du paragraphe 3.2 sur le Prototypage (deuxième portion de code).

    Le code donné dans le cours est le suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    function MaClasse() {
        this.attribut = "valeur";
    }
     
    var obj1 = new MaClasse();
    try {
        obj1.methode(); // Erreur car la méthode n'existe pas pour l'objet
    } catch(err) {
        alert("Erreur: " + err);
    }
     
    MaClasse.prototype = {
        methode: function() {
            alert("Attribut: " + this.attribut);
        }
    }
     
    var obj2 = new MaClasse();
    obj2.methode();
    // Fonctionne correctement car la méthode a été ajoutée au prototype de MaClasse
    Avant ce code, l'auteur écrit:
    Une des caractéristiques importantes du prototypage est que les modifications de l'objet qui lui est associé, sont appliquées sur tous les objets qui vont été instanciés. Par contre, les objets précédemment instanciés ne sont pas impactés.
    Bon, à part la faute de frappe "qui vont été instanciés" au lieu de "qui vont être instanciés", ce qui est faux c'est que les méthodes définies dans l'objet affecté à l'attribut prototype du constructeur s'appliquent aussi aux objets définis avant que cette méthode soit définie: les objets précédemment instanciés sont bien impactés, contrairement à ce qui est dit dans ce cours. Par contre, ce qui est vrai, c'est qu'on ne peut évidemment pas appeler cette méthode avant qu'elle soit définie dans le code, mais dans l'exemple de code ci-dessus donné dans le cours, si on écrit l'instruction obj1.method() après la définition de la méthode methode(), il n'y a pas d'erreur. En fait, comme dans tous langages, on ne peut appeler une fonction avant qu'elle soit définie ou que l'on ai défini son prototype dans le code. Du coup, si on appelle la méthode methode() après sa définition, que l'objet ait été créé avant sa définition ou après ne change rien: l'appel fonctionne bien et ne génère pas une erreur.

    Par exemple, si on teste ce code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     
            function Personne(prenom, nom, age, genre, interets) {
                this.nom = {
                    prenom: prenom,
                    nom: nom
                };
                this.age = age;
                this.genre = genre;
                this.interets = interets;
                this.bio = function() {
                    alert(this.nom.prenom + ' ' + this.nom.nom + ' a ' + this.age + ' ans. Il aime ' + this.interets[0] + ' et ' + this.interets[1] + '.');
                };
                this.salutation = function() {
                    alert('Bonjour ! Je m\'appelle ' + this.nom.prenom + '.');
                };
            };
     
            p4 = new Personne('Arthur', 'Dupont', 33, 'Homme', ['Littérature', 'Informatique']);
            proto = Object.getPrototypeOf(p4);
     
            //Modifiaction du prototype du constructeur Personne
            Personne.prototype.aurevoir = function() {
                alert(this.nom.prenom + ' est sorti. Au revoir !');
            }
    Si on exécute p4.aurevoir() dans la console, on a bien le message "Arthur est sorti. Au revoir" qui s'affiche dans la fenêtre. Tout fonctionne bien, sans générer d'erreur, même si p4 est créée avant de définir la méthode aurevoir().

    A part ça, ça fait un petit moment que je n'avais pas écrit de messages sur le site developpez.com et je n'ai pas trouvé un moyen simple d'écrire un message à l'auteur. Il doit bien il y avoir un lien quelque part, mais je dois commencer à avoir la vue un peu brouillée

    A part ce petit détail, ce cours est très clair et je remercie son auteur.

    A bientôt

  2. #2
    Membre averti
    Profil pro
    Inscrit en
    Août 2004
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2004
    Messages : 32
    Par défaut E,core des questions sur la POO en Javascript
    Bonjour,

    Dans mon premier message, j'avais constaté que la modification de la propriété prototype d'un constructeur affectait aussi les objets créé avant cette modification, mais il semblerait que cela dépende de comment a été modifiée cette propriété.

    En effet, dans le code ci-dessous, on modifie d'abord le prototype du constructeur Personne en ajoutant la méthode saluer(). Dans la console Web, on peut alors constater que l'objet pers1 créé avant cette modification a bien accès à la méthode saluer(), comme l'objet pers2 créé après cette modification.

    Par contre, lorsque la propriété prototype d'un constructeur comme Professeur est modifiée en lui affectant un nouvel objet à l'aide de Object.create(), alors les objets créés avant cette modification ne sont pas affectés. En effet, dans ce cas, l'objet prof1 créé avant de modifier le prototype du constructeur Professeur n'a pas accès à la méthode saluer(), alors que prof2, créé après la modification du prototype du constructeur Professeur, a bien accès à la méthode saluer() héritée du constructeur Personne.

    Voici le code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
     
            // Création d'un constructeur Personne
            function Personne(prenom, nom, age, genre, interets) {
                this.nom = {
                    prenom: prenom,
                    nom: nom
                };
                this.age = age;
                this.genre = genre;
                this.interets = interets;
            };
     
            // pers1 est instancié avant la modification du prototype
            pers1 = new Personne('Arthur', 'Dupont', 32, 'Homme', ['Yoga', 'Programmation']);
     
            // On définit la méthode saluer() dans le prototype
            Personne.prototype.saluer = function() {
                alert('Bonjour ! Je m\'appelle ' + this.nom.prenom + '.');
            };
     
            pers2 = new Personne('Jean-Pierre', 'Lambert', 45, 'Homme', ['Littérature', 'Théatre']);
     
     
            // Création d'un constructeur Professeur
            function Professeur(prenom, nom, age, genre, interets, matiere) {
                Personne.call(this, prenom, nom, age, genre, interets);
                this.matiere = matiere;
            };
     
            // Instanciation d'un Professeur avant la modification du prototype du constructeur
            prof1 = new Professeur('Arthur', 'Dupont', 32, 'Homme', ['Yoga', 'Programmation'], 'Physique');
     
            // Pour que Professeur hérite du prototype de Personne, on créé un objet correspondant au prototype de Personne que l'on affecte à la propriété prototype de Professeur.
            Professeur.prototype = Object.create(Personne.prototype);
     
            // Pour que le constructeur de Professeur soit bien Professeur() et non Personne()
            Professeur.prototype.constructor = Professeur;
     
            prof2 = new Professeur('Jean-Pierre', 'Lambert', 45, 'Homme', ['Littérature', 'Théatre'], 'Français');
    Et voici une copie d'écran des commandes effectuées dans la console Web de Firefox:
    Nom : Console Web.png
Affichages : 119
Taille : 12,6 Ko

    J'aimerai bien y comprendre quelque chose. Je tenterai bien une explication en remarquant que dans le premier cas, la propriété pers1.constructor.prototype pointe toujours sur le même objet après modification du prototype de Personne, alors que lorsque l'on utilise Object.create(), du fait que l'on créé un nouvel objet que l'on affecte à la propriété prototype du constructeur Professeur, on modifie l'adresse de l'objet pointé par Professeur.prototype, alors que celle pointée par prof1.constructor.prototype n'a pas changé.

    Que pensez-vous de cette explication ? Vous paraît-elle juste ?

    En tout cas, ce comportement un peu hasardeux me laisse un peu rêveur sur la programmation objet en Javascript …

    Par ailleurs, ce qui paraît un peu étrange, c'est que la méthode saluer() apparaît bien dans le prototype de prof1 dans la console, alors même que prof1.saluer() conduit à une erreur. Ceci dit, peut-être que la console Web affiche juste le prototype du constructeur lorsqu'on demande l'affichage du prototype d'un objet, même si ces deux prototypes sont différents.

    Est-ce quelqu'un pourrait m'indiquer si mes conclusions sont justes ? Et puis, ce comportement ne vous paraît-il pas étrange ? Car alors, la POO en javascript me semble bien hardue …

    Dans attente de vos commentaires, merci d'avoir lu ce message.

  3. #3
    Membre Expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 910
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 910
    Par défaut
    Salut,

    Je pense que ma réponse précédente à ton premier message répond aussi à ton deuxième message mais j'ajoute quelques précisions...


    Citation Envoyé par Baubeau Cédric Voir le message
    En effet, dans le code ci-dessous, on modifie d'abord le prototype du constructeur Personne en ajoutant la méthode saluer(). Dans la console Web, on peut alors constater que l'objet pers1 créé avant cette modification a bien accès à la méthode saluer(), comme l'objet pers2 créé après cette modification.
    Oui car là on est dans le cas 1.

    Citation Envoyé par Baubeau Cédric Voir le message
    Par contre, lorsque la propriété prototype d'un constructeur comme Professeur est modifiée en lui affectant un nouvel objet à l'aide de Object.create(), alors les objets créés avant cette modification ne sont pas affectés. En effet, dans ce cas, l'objet prof1 créé avant de modifier le prototype du constructeur Professeur n'a pas accès à la méthode saluer(), alors que prof2, créé après la modification du prototype du constructeur Professeur, a bien accès à la méthode saluer() héritée du constructeur Personne.
    Là on est dans le cas 2.

    Citation Envoyé par Baubeau Cédric Voir le message
    Par ailleurs, ce qui paraît un peu étrange, c'est que la méthode saluer() apparaît bien dans le prototype de prof1 dans la console, alors même que prof1.saluer() conduit à une erreur.
    La méthode saluer n'est pas une propriété du prototype de prof1, si elle l'était alors prof1.saluer() ne provoquerait pas d'erreur...

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Août 2004
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2004
    Messages : 32
    Par défaut
    Bonjour,

    Merci Beginner pour ta réponse très claire. Je comprends mieux maintenant les contradictions apparentes que je constatais.

    Cependant, concernant la méthode saluer(), je suis d'accord avec toi lorsque tu dis
    La méthode saluer n'est pas une propriété du prototype de prof1, si elle l'était alors prof1.saluer() ne provoquerait pas d'erreur...
    , mais je disais seulement que c'est étrange que dans la console Web de Firefox, on puisse voir la méthode saluer() lorsque l'on exécute l'instruction prof1.constructor.prototype. Enfin, ce n'est pas étrange, mais c'est finalement un piège, car on pourrait alors penser à tort que cette méthode fait bien partie du prototype de l'objet. En fait, il semblerait que le prototype d'un objet obj ne corresponde pas nécessairement à la propriété obj.constructor.prototype, notamment si le prototype du constructeur a été modifié après la création de l'objet.

  5. #5
    Membre Expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 910
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 910
    Par défaut
    Salut,

    Citation Envoyé par Baubeau Cédric Voir le message
    Avant ce code, l'auteur écrit:
    Une des caractéristiques importantes du prototypage est que les modifications de l'objet qui lui est associé, sont appliquées sur tous les objets qui vont été instanciés. Par contre, les objets précédemment instanciés ne sont pas impactés.
    Bon, à part la faute de frappe "qui vont été instanciés" au lieu de "qui vont être instanciés", ce qui est faux c'est que les méthodes définies dans l'objet affecté à l'attribut prototype du constructeur s'appliquent aussi aux objets définis avant que cette méthode soit définie:...
    Oui et non lol... Il y a une petite subtilité... Il faudrait s'assurer de savoir ce que l'auteur entend par "les modifications de l'objet qui lui est associé"...

    1- Si par "modifications" il veut dire par exemple* qu'on ajoute des propriétés à la propriété prototype de MaClasse alors là effectivement ce n'est pas correcte selon moi lol... (* On peut aussi modifier des propriétés existantes)...

    2- Si par contre il veut dire qu'on affecte à la propriété prototype de MaClasse la référence à un autre objet alors là c'est correcte...

    Pour moi effectivement la phrase de l'auteur correspond au cas 1 (c'est comme cela que je la comprend et c'est vrai que cela pose problème) mais dans son exemple de code on est dans le cas 2 puisqu'on a ceci :

    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    MaClasse.prototype = {
        methode: function() {
            alert("Attribut: " + this.attribut);
        }
    }

    Ici on affecte à MaClasse.prototype la référence à un nouvel objet... On écrase donc l'ancienne référence (c'-à-d la référence qui était contenue dans MaClasse.prototype avant cette affectation)...

    L'objet obj1 a été crée avant cette affectation par conséquent son prototype** pointe vers l'ancienne référence et non vers la référence à ce nouvel objet.

    ---> Pour clarifier : si tu fais console.log(obj1.__proto__ === MaClasse.prototype); tu obtiens true avant l'affectation et false après.

    ** Petite parenthèse : pour récupérer le prototype de obj1 on peut faire obj1.__proto__ ou ce qui est mieux : Object.getPrototypeOf(obj1)...

    Ainsi dans ce cas 2 il est vrai qu'on peut dire que "les objets précédemment instanciés ne sont pas impactés" mais cela est faux dans le cas 1.


    Citation Envoyé par Baubeau Cédric Voir le message
    ...ce qui est faux c'est que les méthodes définies dans l'objet affecté à l'attribut prototype du constructeur s'appliquent aussi aux objets définis avant que cette méthode soit définie: les objets précédemment instanciés sont bien impactés, contrairement à ce qui est dit dans ce cours.
    Ce que tu dis est vrai dans le cas 1 mais pas dans le cas 2.

    Citation Envoyé par Baubeau Cédric Voir le message
    Par contre, ce qui est vrai, c'est qu'on ne peut évidemment pas appeler cette méthode avant qu'elle soit définie dans le code, mais dans l'exemple de code ci-dessus donné dans le cours, si on écrit l'instruction obj1.method() après la définition de la méthode methode(), il n'y a pas d'erreur. En fait, comme dans tous langages, on ne peut appeler une fonction avant qu'elle soit définie ou que l'on ai défini son prototype dans le code. Du coup, si on appelle la méthode methode() après sa définition, que l'objet ait été créé avant sa définition ou après ne change rien: l'appel fonctionne bien et ne génère pas une erreur.
    Ben non justement, il suffit de tester, ceci : obj1.method() provoque une erreur que cette instruction soit placée avant ou après la définition de la méthode method...

    Et ce parce qu'on est dans le cas 2... En effet dans ce cas 2 le prototype de l'objet obj1 ne pointe pas vers le nouvel objet ayant la propriété method comme on l'a vu ci-dessus...

    Citation Envoyé par Baubeau Cédric Voir le message
    Par exemple, si on teste ce code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     
            function Personne(prenom, nom, age, genre, interets) {
                this.nom = {
                    prenom: prenom,
                    nom: nom
                };
                this.age = age;
                this.genre = genre;
                this.interets = interets;
                this.bio = function() {
                    alert(this.nom.prenom + ' ' + this.nom.nom + ' a ' + this.age + ' ans. Il aime ' + this.interets[0] + ' et ' + this.interets[1] + '.');
                };
                this.salutation = function() {
                    alert('Bonjour ! Je m\'appelle ' + this.nom.prenom + '.');
                };
            };
     
            p4 = new Personne('Arthur', 'Dupont', 33, 'Homme', ['Littérature', 'Informatique']);
            proto = Object.getPrototypeOf(p4);
     
            //Modifiaction du prototype du constructeur Personne
            Personne.prototype.aurevoir = function() {
                alert(this.nom.prenom + ' est sorti. Au revoir !');
            }
    Si on exécute p4.aurevoir() dans la console, on a bien le message "Arthur est sorti. Au revoir" qui s'affiche dans la fenêtre. Tout fonctionne bien, sans générer d'erreur, même si p4 est créée avant de définir la méthode aurevoir().
    Oui là cela fonctionne car cette fois nous sommes dans le cas 1.

    En effet quand tu fais Personne.prototype.aurevoir = function() {...} tu ajoutes la méthode aurevoir à la propriété prototype de Personne. Ici on n'affecte pas à la propriété prototype de Personne une nouvelle référence (la référence à un nouvel objet)... Personne.prototype contient toujours la même référence...

    ---> Pour être clair ceci console.log(p4.__proto__ === Personne.prototype); affiche toujours true, que ce soit avant ou après cet ajout de la méthode aurevoir ...

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 7
    Dernier message: 27/05/2013, 12h33
  2. Question sur un cours (besoin d'explications)
    Par humanite dans le forum Débuter
    Réponses: 17
    Dernier message: 08/01/2013, 23h47
  3. Réponses: 2
    Dernier message: 25/11/2008, 22h07
  4. Question sur le cours "Introduction au traitement numérique d'image"
    Par yostane dans le forum Traitement d'images
    Réponses: 1
    Dernier message: 13/09/2008, 13h13
  5. Deux questions sur un cours SGBD
    Par Francois_quad dans le forum Débuter
    Réponses: 3
    Dernier message: 17/01/2007, 17h40

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo