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 :

Bonnes pratiques pour la POO en Javascript


Sujet :

JavaScript

  1. #1
    Membre régulier
    Inscrit en
    Décembre 2003
    Messages
    87
    Détails du profil
    Informations forums :
    Inscription : Décembre 2003
    Messages : 87
    Points : 87
    Points
    87
    Par défaut Bonnes pratiques pour la POO en Javascript
    Bonjour,

    Je débute en javascript et tente de prendre de bonnes habitudes dès le début. Je suis habitué au C++ et Java et ait donc l'habitude d’écrire des interfaces et des classes séparées dans des fichiers différents en important les différences dépendances.

    J'ai donc deux questions:
    1. Quelle syntaxe préférer pour l'écriture de "classes" en Javascript?
    2. Comment organiser ses différents fichiers sources et gérer les dépendances entre ces derniers?


    J'ai trouvé des personnes conseillant d'utiliser minimize pour faire un seul fichier avec les différents fichiers sources. D'autres conseillent d'utiliser des modules avec require.js...

    Pour être plus concret je suis en train de m'amuser avec processing.js pour faire du rendu dans un canvas. En programmeur habitué a la POO traditionnelle je pensais faire une interface commune pour toutes mes entitées Drawable, puis définir des entités de bases genre Circle, Square, Polygon... Comment feriez-vous cela en Javascript?

  2. #2
    Rédacteur/Modérateur

    Avatar de SylvainPV
    Profil pro
    Inscrit en
    Novembre 2012
    Messages
    3 375
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2012
    Messages : 3 375
    Points : 9 944
    Points
    9 944
    Par défaut
    Il faut éviter d'écrire du Javascript de la même manière qu'on voudrait l'écrire en Java. La programmation objet orientée prototype est différente de la programmation objet par classes. Même si on peut parvenir à retrouver une syntaxe et un mode de pensée plus proche des classes, c'est selon moi dénaturer le langage et passer à côté d'autres spécificités. Comme quand on traduit de l'anglais en chinois traditionnel, on peut se faire comprendre mais on perd énormément de nuances et de subtilités dans le propos.

    Par rapport aux conseils que tu as entendu : ils sont bons, mais je te conseillerais d'apprendre à marcher avant d'apprendre à courir requireJS est un outil très pratique pour gérer de nombreuses dépendances, pour les projets assez importants, mais qui requiert une certaine discipline dans le code. Et les concaténeurs/minifieurs tels que minimize interviennent après, quand il s'agit de booster les performances de ton site en compressant tout ce que tu peux. Je pense que tu n'en es pas encore là, inutile d'anticiper trop sous peine de t'y perdre.
    One Web to rule them all

  3. #3
    Membre émérite
    Avatar de Kaamo
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    1 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 1 165
    Points : 2 778
    Points
    2 778
    Par défaut
    Les interfaces n'ont en effet rien à faire en Javascript.
    Pour compléter les propos de Sylvain :

    En JavaScript, on ne teste pas qu'un objet appartient à telle classe ou implémente telle interface. Cela n'a pas de sens car un objet JavaScript n'entre dans aucun moule préalablement défini

    En gros, en JavaScript, tu ne crées pas un objet à partir d'un moule (classe) qui doit implémenter telle interface, mais tu crées un objet A à partir d'un autre objet B. B devient alors le prototype de A. Le prototype "racine" étant Object.
    Le nouvel objet B ainsi créé à partir de A aura ses propres méthodes/attributs et aura également accès à celles de A, puis ensuite à celles du prototype de A, etc. On parle de chaîne de prototype. Si la propriété/méthode n'est pas dans B, on check dans son prototype A, puis dans le prototype du prototype A, etc, jusqu'à remonter la pile jusqu'à Object.

    Un "équivalent" de l'interface serait plutôt de tester la présence d'attributs ou de méthodes.

    En effet, JavaScript répond au style "duck typing". Si mon objet à la méthode "coincoin()" et qu'il a un bec, alors cet objet est un canard. Sinon ce n'en est pas un.

    Voici un cas ultra basique pour simuler une notion "d'interface". On check si l'objet courant possède les propriétés imposées par l'interface qui est en réalité un objet classique recensant les types de propriétés attendues. Attention, si l'objet courant contient plus de propriétés, ce bout de code ne le détecte pas. Bref, c'est simplement pour imager la chose :

    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
    // l'objet implémente - t - il l'interface ?
    Object.prototype.implemente = function(interface){ 
      for(var prop in interface) if (interface.hasOwnProperty(prop)) {
        if(typeof this[prop] !== interface[prop] || this[prop] === undefined)
          return false;
      }
      return true;
    };
     
     
    var interfaceCochon = {
      hasGroin: "boolean",
      groingroin: "function",
      couleur: "string"
    }; 
     
    var interfaceCanard = {
      hasBec: "boolean",
      coincoin: "function"
    }; 
     
    var objetCanard = {
      hasBec: true,
      coincoin: function() { console.log('coin coin'); }
    }
     
    console.log(objetCanard.implemente(interfaceCochon)); // false
    console.log(objetCanard.implemente(interfaceCanard)); // true
    Mais ça n'a pas de sens car c'est un langage dynamique. A la création de l'objet, peut-être que objetCanard se pliera aux exigences d'une interface quelconque. Mais quid de modifier ensuite l'interface ? Ou l'objet sans revérifier si l'implémentation est donne ?

  4. #4
    Membre régulier
    Inscrit en
    Décembre 2003
    Messages
    87
    Détails du profil
    Informations forums :
    Inscription : Décembre 2003
    Messages : 87
    Points : 87
    Points
    87
    Par défaut
    Merci pour vos réponses. Je vais abandonner l'utilisation d'un framework pour l'instant afin de bien comprendre ce que je fais.

    Si j'ai bien compris, mon exemple de formes à dessiner donnerai le code 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
    function Square(size) {
        this.size = size;
    }
    Square.prototype.draw = function() { return "Square of size: " + this.size; }
     
    function Circle(radius) {
        this.radius = radius;
    }
    Circle.prototype.draw = function() { return "Circle of radius: " + this.radius; }
     
    var entities = [];
    entities.push(new Square(10));
    entities.push(new Square(20));
    entities.push(new Circle(30));
     
    for ( var i = 0; i < entities.length; i++ ) {
        console.log( entities[i].draw() );
    }
    Est-ce que cela vous parait correct?
    Pour l'organisation du code source comment procéderiez-vous?

    1 fichier circle.js, 1 fichier square.js et un fichier main.js inclus dans cet ordre la dans le code html?
    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <!DOCTYPE html>
    <html>
      <head>...</head>
      <body>
        ...
        <script src="js/circle.js"></script>
        <script src="js/square.js"></script>
        <script src="js/main.js"></script>
      </body>
    </html>

  5. #5
    Membre émérite
    Avatar de Kaamo
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    1 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 1 165
    Points : 2 778
    Points
    2 778
    Par défaut
    Est-ce que cela vous parait correct?
    C'est une possibilité, personnellement je n'y adhère pas.


    Pour illustrer ce que j'ai dit ci-dessus et pour répondre à ta question.
    Quelle syntaxe préférer pour l'écriture de "classes" en Javascript?
    Il n'y a donc pas de classe comme tu l'entends. Juste des objets qui contiennent des attributs et de méthodes et qui peuvent être "parents" (prototype) d'autres objets.

    La magie des prototypes chaînés fait le reste

    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
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    /* Pour les navigateurs n'implémentant pas ES5 */
    if (!Object.create) {
      Object.create = function(o) {
        function F() {}
        F.prototype = o;
        return new F();
      };
    }
     
    // Voici un objet, nommé Animal. Implicitement, son prototype est Object
    var Animal = {
      init: function(type, nom) {
        this.type = type;
        this.nom = nom;
      },
      presenter: function() {
        return "Je suis un " + this.type + " et je me prénomine " + this.nom + " ! ";
      }
    };
     
    // Voici un autre objet, Canard. Explicitement, on le créé à partir de Animal. Le prototype de Canard est donc Animal.
    var Canard = Object.create(Animal);
    // cette méthode ne sera disponible que pour cet objet Canard et les objets susceptibles d'être créés à partir de lui
    Canard.crier = function() {
      return "coin coin !";
    };
     
    // Voici un autre objet, Cochon. Explicitement, on le créé à partir de Animal. Le prototype de Cochon est donc Animal.
    var Cochon = Object.create(Animal);
    // cette méthode ne sera disponible que pour cet objet Cochon et les objets susceptibles d'être créés à partir de lui
    Cochon.crier = function() {
      return "groin groin !";
    };
     
    // création d'un objet canard1, créé à partir de Canard.
    // chaine de prototype : canard1 > Canard > Animal > Object
    var canard1 = Object.create(Canard);
    canard1.init("canard célèbre", "Donald"); // canard1 n'a pas de méthode init(), on check dans le prototype direct, de Canard donc puis Animal.
    console.log(canard1.presenter()); // méthode de Animal
    console.log(canard1.crier()); // méthode de Canard
     
    // chaine de prototype : cochon1 > Cochon > Animal > Object
    var cochon1 = Object.create(Cochon);
    cochon1.init("cochon grimpeur", "Super cochon"); // On check dans cochon1, la méthode init n'existe pas. Du coup, on descend la chaine de prototype, et on check dans Cochon, etc .... jusqu'à Animal
    console.log(cochon1.presenter()); // méthode de Animal
    console.log(cochon1.crier()); // méthode de Cochon
     
    // Pour checker les prototypes
    console.log(Animal.isPrototypeOf(cochon1)); // true
    console.log(Animal.isPrototypeOf(canard1)); // true
    console.log(Animal.isPrototypeOf(Canard)); // true
    console.log(Canard.isPrototypeOf(canard1)); // true
    console.log(Canard.isPrototypeOf(cochon1)); // false
    Ouputs :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Je suis un canard célèbre et je me prénomine Donald ! 
    coin coin !
    Je suis un cochon grimpeur et je me prénomine Super cochon ! 
    groin groin !
    true
    true
    true
    true
    false

  6. #6
    Expert éminent
    Avatar de sekaijin
    Homme Profil pro
    Urbaniste
    Inscrit en
    Juillet 2004
    Messages
    4 205
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Urbaniste
    Secteur : Santé

    Informations forums :
    Inscription : Juillet 2004
    Messages : 4 205
    Points : 9 127
    Points
    9 127
    Par défaut
    Citation Envoyé par piemur2000 Voir le message
    Bonjour,

    Je débute en javascript et tente de prendre de bonnes habitudes dès le début. Je suis habitué au C++ et Java et ait donc l'habitude d’écrire des interfaces et des classes séparées dans des fichiers différents en important les différences dépendances.

    J'ai donc deux questions:
    1. Quelle syntaxe préférer pour l'écriture de "classes" en Javascript?
    1. ben la première règle est d'oublier les classes.
      qui dit pas de classe dit pas de question sur le sujet.
      JS est un langage à base de prototype donc il suffit d'écrire des prototypes.
      Citation Envoyé par piemur2000 Voir le message
    2. Comment organiser ses différents fichiers sources et gérer les dépendances entre ces derniers?
    tout dépends de ce que tu fais et pour qui tu le fais. pour une appli interne sur un intranet avoir des fichiers multiples n'est pas un pb
    si tu est sur internet pour une appli grand public mieux vaut un seul fichier.

    reste donc comment organiser sont travail et ça, ça ne relève pas de bonne pratique d'un langage mais d'une méthode de travail.

    dans le premier cas tu vas prendre tes fichier js et les mettre sur ton serveur
    dans le deuxième tu vas prendre un outil qui prendra tes fichier JS et en fera un seul fichier (ex sencha cmd)
Citation Envoyé par piemur2000 Voir le message

J'ai trouvé des personnes conseillant d'utiliser minimize pour faire un seul fichier avec les différents fichiers sources. D'autres conseillent d'utiliser des modules avec require.js...

Pour être plus concret je suis en train de m'amuser avec processing.js pour faire du rendu dans un canvas. En programmeur habitué a la POO traditionnelle je pensais faire une interface commune pour toutes mes entitées Drawable, puis définir des entités de bases genre Circle, Square, Polygon... Comment feriez-vous cela en Javascript?
exactement comme en java c++ python, tcl, xLisp, smalltalk, Ada, objective-C ou Pascal pour les quelques qui me viennent à l'esprit
perso quelque soit le langage putôt que qu'une interface je ferais une classe de base. donc en JS je ferais un prototype.

ce qu'il faut bien comprendre avec JS c'est que les objets peuvent savoir des attributs et des méthodes qui ne sont pas héritées.

on peut voir ça comme des références en C++
on peut dynamiquement ajouter ou enlever des référnence à un objet.
du coup les interfaces n'ont pas de sens. par simple affectation de methode et d'attribut on peut implémenter un héritage multiple.

imagine que tu ais des classes qui hérite d'une classe mathématique Geometric qui est la classe mère des forme géométriques. tes classes Circle Rect héritent au travers de cette classe des notion mathématiques de géometrie.

puis tu as à côté un ensemble de classes pour faire du dessin la classe de base étant Drawable. elle contient tout le nécessaire pour gérer un caneva et dessier dedans.

il te suffit de faire hérité Circle de Géométric et de Drawable pour avoir accès à toutes les propriétés de Geometric et de Drawable.

alors qu'avec C++ et Java tu ne peut avoir qu'un héritage simple. du coup pour rendre tes classe Circle et Rect dessinable tu fait une interface et dans chaqu'une tu implemente toute les méthodes nécéssaires.
avec l'héritage multiple ce n'est plus nécéssaire.

avec la possibilité d'ajouter ou de retirer dynamiquement des méthodes ou des attributs il n'est plus possible de se baser sur les "Classes" ou "Interfaces" pour savoir de quoi est capable un objet. les opérateur de type "instance of" de java qui permet de savoir si un objet possède certaine capacité n'est plus sufisant. la capacité a pu être supprimé.

à la place il suffit de tester directement l'existance de la méthodes et sa nature.

A+JYT

+ Répondre à la discussion
ActualitésF.A.Q JSTUTORIELS JSSOURCES JSEXERCICES JSLIVRES JSQUIZZ JS

Discussions similaires

  1. Bonne pratique pour inclure source de projet open source ?
    Par joseph_p dans le forum Eclipse Java
    Réponses: 3
    Dernier message: 05/07/2007, 21h51
  2. Réponses: 5
    Dernier message: 12/09/2006, 18h06
  3. Tutoriel SEO : Introduction et bonnes pratiques pour l'optimisation de pages Web
    Par Community Management dans le forum Référencement
    Réponses: 0
    Dernier message: 06/07/2006, 00h03

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