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 :

[OO] Implémentation de l'héritage ET d'appels super()


Sujet :

JavaScript

  1. #21
    Rédacteur

    Avatar de Bovino
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juin 2008
    Messages
    23 647
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 23 647
    Points : 91 220
    Points
    91 220
    Billets dans le blog
    20
    Par défaut
    Citation Envoyé par mekal
    a chaque que je voit une conversation sur la poo je me dit que c'est vraiment de la merde car il n'y a jamais reelement de resolution au probleme et que l'on se retrouve rapidement dans du charabia qui ne motive pas a apprendre la poo car si on l'apprend et au finale on se retrouver a se poser un miliard de questions a savoir quelle est la meilleur facon d'utiliser la poo pourquoi l'apprendre ? sans compter que l'on ne voit jamais d'exemple pratique reel a l'inverse du virtuelle que l'on rencontre tout le temp dans son utilisation.
    Tu devrais regarder du coté des contributions pour voir concrètement ce que la POO peut apporter à JavaScript...
    Au hasard (et pas du tout pour m'auto-citer mais parce que comme Willpower je trouve ça beau ) : Fondu enchainé

    Citation Envoyé par mekal
    et vive le procedurale
    D'accord, mais encore une fois, il n'y a pas à proprement parler de syntaxe procédurale en JavaScript
    Rends-toi compte que lorsque tu écris document.getElementById(), c'est déjà de l'OO

  2. #22
    Membre régulier
    Profil pro
    Étudiant
    Inscrit en
    Janvier 2008
    Messages
    253
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2008
    Messages : 253
    Points : 84
    Points
    84
    Par défaut
    Oui c'est beau en effet, le débat est instructif.

    Est-il possible déclarer le code constructeur d'une classe déclarée par une fonction comme une fonction (et non dans le corps de la fonction constituant l'objet)?

    Je reprends quelques classes en Java et PHP actuellement et ça serait bien de compléter le dispositif par un code du genre :
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    function MaClasse (arg1, arg2){ // Signature identique
     
      this.__construct (arg1, arg2){ // PHP-like
         // statements
      }
     
      // Déclaration des membres
    }
    et lorsque l'on demande le new, this.__construct(arg1, arg2) est exécutée automatiquement.

    C'est un bonus mais ca me simplifierai bien les choses.

    Merci à vous.

  3. #23
    Membre expérimenté Avatar de Willpower
    Homme Profil pro
    sans emploi
    Inscrit en
    Décembre 2010
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : sans emploi

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 009
    Points : 1 519
    Points
    1 519
    Par défaut
    Citation Envoyé par fanfouer Voir le message
    Oui c'est beau en effet, le débat est instructif.

    Est-il possible déclarer le code constructeur d'une classe déclarée par une fonction comme une fonction (et non dans le corps de la fonction constituant l'objet)?

    Je reprends quelques classes en Java et PHP actuellement et ça serait bien de compléter le dispositif par un code du genre :
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    function MaClasse (arg1, arg2){ // Signature identique
     
      this.__construct (arg1, arg2){ // PHP-like
         // statements
      }
     
      // Déclaration des membres
    }
    et lorsque l'on demande le new, this.__construct(arg1, arg2) est exécutée automatiquement.

    C'est un bonus mais ca me simplifierai bien les choses.

    Merci à vous.
    utilises-tu parfois le constructeur sans construire ? si oui, peux-tu montrer un exemple stp ?

    enfin, peut-être que ceci t'aidera :
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    function MaClasse (arg1, arg2){ // Signature identique
     
      this.__construct (arg1, arg2){ // PHP-like
         // statements
      }
     
      // Déclaration des membres
     
      // Si l'objet courant est une instance de la fonction courante 
      if(this instanceof arguments.callee)
        this.__construct (arg1, arg2);
    }

    tu peux même aller plus loin pour tester s'il n'a pas encore été construit :
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    function MaClasse (arg1, arg2){ // Signature identique
     
      this.__construct (arg1, arg2){ // PHP-like
         // statements
         this.DEFINE = 1;
      }
     
      // Déclaration des membres
     
      // Si l'objet courant est une instance de la fonction courante 
      if(this instanceof arguments.callee && !this.DEFINE)
        this.__construct (arg1, arg2);
    }

    mais en fait, j'ai du mal à voir comment c'est utilisé donc je ne suis pas sûr que mes remarques soient pertinentes ..


    edit:
    en fait en javascript la définition de la classe est le constructeur. le concept de class n'existe pas mais peut être palier par les prototypes.

    exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    function maClass(){
      // ceci est un constructeur
    }
    maClass.prototype.foo = function(){};
    maClass.prototype.bar = function(){};
    tu ne peux pas définir plusieurs constructeurs mais il te suffit de faire le tri dans l'exécution du constructeur unique, le nombre de paramètre n'est pas défini et peut être testé comme suit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    function maClass(){
      if(arguments.length == 2 )
          execConstructeurDeuxArgs(arguments[0],arguments[1]);
    }
    edit:

    dans d'autre langage, le fait de déclarer la classe séparement de son constructeur permet de définir des type de variable sans les instancier ex :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class c{
    }
     
    c objetC; // instancie un objet
    c functionRenvoyantUnObjetC(); // déclare une fonction qui renverra un c
    or en javascript on ne doit(peut) pas déclarer de type, toutes les variables sont des "var" et leurs type change selon ce que l'ont leurs assigne.

  4. #24
    Membre régulier
    Profil pro
    Étudiant
    Inscrit en
    Janvier 2008
    Messages
    253
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2008
    Messages : 253
    Points : 84
    Points
    84
    Par défaut
    Citation Envoyé par Willpower Voir le message
    utilises-tu parfois le constructeur sans construire ? si oui, peux-tu montrer un exemple stp ?
    Non c'est vrai, mais dans mes classes le constructeur est toujours une méthode publique, pas dans le corps immédiat de la déclaration de la classe (c'est un unique problème de forme du code).


    Ton code correspond bien au besoin, mais serait-il possible d'inclure ce passage :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    if(this instanceof arguments.callee)
        this.__construct (arg1, arg2);
    Dans une modification du prototype de Function?

  5. #25
    Membre expérimenté Avatar de Willpower
    Homme Profil pro
    sans emploi
    Inscrit en
    Décembre 2010
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : sans emploi

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 009
    Points : 1 519
    Points
    1 519
    Par défaut
    Citation Envoyé par fanfouer Voir le message
    Non c'est vrai, mais dans mes classes le constructeur est toujours une méthode publique, pas dans le corps immédiat de la déclaration de la classe (c'est un unique problème de forme du code).


    Ton code correspond bien au besoin, mais serait-il possible d'inclure ce passage :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    if(this instanceof arguments.callee)
        this.__construct (arg1, arg2);
    Dans une modification du prototype de Function?
    Si chaque appel à "maClasse" crée un nouvelle objet, tu ne dois même pas mettre de condition, juste rajouter l'exécution du constructeur en fin :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function MaClasse (arg1, arg2){ // Signature identique
      // déclaration du constructeur
      this.__construct (arg1, arg2){ // PHP-like
         // statements
      }
     
      // Déclaration des membres
      // ....
     
      // Appel au constructeur
      this.__construct(arg1, arg2);
    }
    mais ça n'a pas beaucoup de sens, autant mettre les lignes du constructeur en dehors (dans le corps de la classe).


    edit:
    pour un constructeur de copie, tu peux tester les paramètres :

    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 MaClasse (arg1, arg2){ // Signature identique
      // déclaration du constructeur
      this.__construct(arg1, arg2){ // PHP-like
         // statements
      }
      this.__copy(objet){ // PHP-like
         // statements
      }
     
      // Déclaration des membres
      // ....
     
      // Appel au constructeur
      if(arguments.length == 1 && arg1 instanceof MaClasse)
        return  this.__copy(arg1);
      // else (implicite à cause du "return")
      this.__construct(arg1, arg2);
    }

  6. #26
    Membre régulier
    Profil pro
    Étudiant
    Inscrit en
    Janvier 2008
    Messages
    253
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2008
    Messages : 253
    Points : 84
    Points
    84
    Par défaut
    Je suis d'accord mais peut-on s'éviter de mettre cette ligne au bas de chaque classe et de faire que tout appel de new MaClasse() déclenche l’exécution de la méthode __construct()?

    Autre problème existentiel : le self

    En fait quand j'écris ca :
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    var MaClasse = function (){
     
      this.func = function (){
         // Accès à une propriété statique :
         alert (MaClasse.STATIC);
      }
    }
     
    MaClasse.STATIC = "1";
    Je suis obligé de remettre le nom de la classe pour accéder aux membres statiques.
    Existerait-il un moyen (toujours en modifiant le prototype de Function je pense) de créer un self faisant référence à cette classe?
    Généralement j'utilise des espaces de noms en grand nombre et le jour où un des NS change de nom, je serai content de ne pas avoir à corriger des dizaines de fichiers.

    Merci par avance.

  7. #27
    Membre expérimenté Avatar de Willpower
    Homme Profil pro
    sans emploi
    Inscrit en
    Décembre 2010
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : sans emploi

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 009
    Points : 1 519
    Points
    1 519
    Par défaut
    Citation Envoyé par fanfouer Voir le message
    Je suis d'accord mais peut-on s'éviter de mettre cette ligne au bas de chaque classe et de faire que tout appel de new MaClasse() déclenche l’exécution de la méthode __construct()?

    Autre problème existanciel, qui faisais parti des questions de départ : le self

    En fait quand j'écris ca :
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    var MaClasse = function (){
     
      this.func = function (){
         // Accès à une propriété statique :
         alert (MaClasse.STATIC);
      }
    }
     
    MaClasse.STATIC = "1";
    Je suis obligé de remettre le nom de la classe pour accéder aux membres statiques.
    Existerait-il un moyen (toujours en modifiant le prototype de Function je pense) de créer un self faisant référence à cette classe?
    Généralement j'utilise des espaces de noms en grand nombre et le jour où un des NS change de nom, je serai content de ne pas avoir à corriger des dizaines de fichiers.

    Merci par avance.
    A mon avis tu cherches à faire qqe chose comme ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    var MaClasse = function (){
      this.func = function (){
         // Accès à une propriété statique :
         alert (this.STATIC.valeur);
      }
    }
    MaClasse.prototype.STATIC = {valeur:1}:
    Si je faisais

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MaClasse.prototype.valeur = 1;
    Cela n'aurait pas une valeur statique car les nombres(ainsi que les strings) assignent des valeurs et non des pointeurs et donc si l'on crée 2 objets(a & b) de type "maClasse" et que sur l'un on fait "a.valeur = 2". ça ne modifiera que a.valeur et non b.valeur.

    Tandis qu'en créant un objet (que j'ai nommé STATIC) a.STATIC et b.STATIC pointeront vers le même objet et modifier "a.STATIC.valeur = 2" modifiera donc l'objet partagé avec b.


    edit:

    voici un exemple que tu peux tester :

    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
    var MaClasse = function (){
      this.func = function (){
         // Accès à une propriété statique :
         alert (this.value);
      }
    }
    MaClasse.prototype.value = 1;
     
    var a = new MaClasse();
    var b = new MaClasse();
    b.value = 2;
    a.func(); // 1 -> mauvais
     
    //----------------
     
    var MaClasse = function (){
      this.func = function (){
         // Accès à une propriété statique :
         alert (this.STATIC.value);
      }
    }
    MaClasse.prototype.STATIC = {};
     
    var a = new MaClasse();
    var b = new MaClasse();
    b.STATIC.value = 2;
    a.func(); // 2 -> bon

  8. #28
    Membre régulier
    Profil pro
    Étudiant
    Inscrit en
    Janvier 2008
    Messages
    253
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2008
    Messages : 253
    Points : 84
    Points
    84
    Par défaut
    Citation Envoyé par Willpower Voir le message
    Si je faisais

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MaClasse.prototype.valeur = 1;
    Oui mais là c'est normal que ce ne soit pas un membre statique : tu place "valeur" dans le prototype.
    Robert Nymann préconise d'utiliser directement MaClasse.valeur pour créer un membre statique.

    Sinon après le reste du code est bien cohérent : tu as bien recréer une valeur statique en utilisant un pointeur.

  9. #29
    Membre expérimenté Avatar de Willpower
    Homme Profil pro
    sans emploi
    Inscrit en
    Décembre 2010
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : sans emploi

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 009
    Points : 1 519
    Points
    1 519
    Par défaut
    Citation Envoyé par fanfouer Voir le message
    Je suis d'accord mais peut-on s'éviter de mettre cette ligne au bas de chaque classe et de faire que tout appel de new MaClasse() déclenche l’exécution de la méthode __construct()?

    A priori oui et non.

    Mais le plus simple et le plus propre serait quand même de modifier tout. (par exemple avec la fonction "replace" de ton éditeur)

    Sinon, si toutes tes classes sont définies dans un objet du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    var Classes = {};
    Classes.maClasse1 = function(){};
    Classes.maClasse2 = function(){};
    Classes.maClasse3 = function(){};
    Tu peux faire une boucle vraiment sale sur "Classes" du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for(var i in Classes)
      Classes[i] = Classes[i].toString.replace(/}$/,"this.__construct();}"); // un truc du genre, j'suis nul en regExp
    Ou alors

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    for(var i in Classes)
      Classes[i] = (function(fn){
        return function(){
          var o = this;
          if(this instanceof arguments.callee){
            var proto = function(){};
            proto.prototype = fn.prototype;
            o = new proto();
          }
          fn.apply(o,arguments);
          return o.__construct();
      };
    })(Classes[i]);
    Mais je pense que ça ne s'adapte pas vraiment aux "new". (en tout cas, tu rencontreras des complications avec cette 2ème solution.) (j'ai édité, ça devrait fonctionner mnt avec les new mais ça reste sale)

    Bref, je pense(quasi certain) qu'il est impossible de rajouter (sans rédéfinir) du code dans l’exécution d'une fonction (classe)

  10. #30
    Membre régulier
    Profil pro
    Étudiant
    Inscrit en
    Janvier 2008
    Messages
    253
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2008
    Messages : 253
    Points : 84
    Points
    84
    Par défaut
    D'accord j'en prend bonne note, je vais donc rajouter ma ligne en bas de chaque classe ce sera globalement plus simple.

    Pour l'histoire du self qu'en penses-tu?
    J'ai pensé à compléter le prototype de Function avec une fonction self() qui retournerai l'objet javascript correspondant à la classe de l'objet appelant (ca ne marchera que dans le cadre de méthodes d'instance) pour ensuite accéder au membre souhaité sans utiliser de pointeur et donc de sous-champ value (dont le nom reste arbitraire et que je vais oublier régulièrement).

    Je ne sais pas si c'est très clair, voici un code :
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    Function.prototype.self = function(){
        //<- ???
    }
     
    // ----------------
     
    MaClasse = function (){
       this.func = function(){
          alert(self().MA_VALEUR_STATIQUE); // Est sensé affiché 1, self() renvoi ici MaClasse.
       }
    }
     
    MaClasse.MA_VALEUR_STATIQUE = "1";

    Mais je ne sais pas comment, à partir de l'objet courant, obtenir le pointeur vers le constructeur de MaClasse.

    Il ne me manque plus que ce détail-ci pour y voir un peu plus clair.

  11. #31
    Membre expérimenté Avatar de Willpower
    Homme Profil pro
    sans emploi
    Inscrit en
    Décembre 2010
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : sans emploi

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 009
    Points : 1 519
    Points
    1 519
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    MaClasse = function (){
       this.func = function(){
          alert(this.constructor.MA_VALEUR_STATIQUE); 
       }
    }
    MaClasse.MA_VALEUR_STATIQUE = "1";
    // --- exemple d'utilisation ---
    var e = new MaClasse();
    e.func();

    mais bon, en général quand on code en javascript on pense différemment, plutôt :

    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
    // enclosure pour limiter le scope de variables
    (function(){ 
    // MON CODE
    // window.variables_publiques = 1; 
    // var variables_privées = 1; 
       // --- déclaration d'une classe et d'une valeur statique ---
       function MaClasse(){
          this.func = function(){alert(this.static.value);};
          this.static.value = this.static.value || 1; // s'il existe, ne rien faire sinon vaut 1
       }
       MaClasse.prototype.static = {};
       // --- exemple d'utilisation ---
       var objet1 = new MaClasse();
       var objet2 = new MaClasse();
       objet1.func(); // 1
       // modification de la valeur statique via un objet
       objet2.static.value = 2;
       objet1.func(); // 2
    // fin de la closure
    })();

  12. #32
    Invité
    Invité(e)
    Par défaut
    par contre ton dernier exemple n'a plus grand chose à voir avec l'héritage, tu fais juste appel à un constructeur d'objet contenant des fonctions.
    Oui, c'est pas de l'héritage à proprement parler, mais s'en est tout comme. La différence, c'est que l'appelant externe n'a accès qu'à la méthode de premier niveau ou alors, il faut créer un namespace style super ou _ubber; et que les membres protégés sont accessibles par un objet param.

    Donc effectivement, si on veut aller en profondeur, la gestion d'un super est identique (donc moins bien puisqu'il faut s'embêter nous même) que passer par l'approche prototypale. Cela dit, on a rarement vu un obj.prototype.prototype.hello();, du coup, dans le pire des cas, plutot que de passer par super, on peut passer des méthodes communes dans param, donc either
    param.sayHello=function(){}; ou param.A={sayHello:function(){}} si on craint les conflits

    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
    <html>
    <head>
    <script type="text/javascript">
    function A(param){
            //update param with protected members
            param.value=1;
            var obj={hard:function(){return 'hello'}};
    	return obj;//directly returns a contructed obj instead of its members
    }
    function B(){
      var obj={};
      var myA = A(obj);
      var c = myA.hard;
      myA.hard = function(){//decorator
       return c()+'lol '+obj.value;
      };
      return myA;
    }
    var myB=B();
    alert(myB.hard());//hellolol 1
    </script>
    </head>
    </html>

  13. #33
    Invité
    Invité(e)
    Par défaut
    pour ce qui est de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    for(var i in Classes)
      Classes[i] = (function(fn){
        return function(){
          var o = this;
          if(this instanceof arguments.callee){
            var proto = function(){};
            proto.prototype = fn.prototype;
            o = new proto();
          }
          fn.apply(o,arguments);
          return o.__construct();
      };
    })(Classes[i]);
    c'est la même chose que faire un new en fait (vu qu'on construit).
    Ca revient donc à faire un encapsulant qui donne qqch dustyle
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    var myA = classes.New(A, args);
    classes.New = function(A, args){
     var a = new A(args);
     a.__construct(args);//avec construction différée.
     return a;
    }
    cela dit, ca ne sert à rien. Autant construire directos comme l'a dit willpower.

    Sinon, pour le coup de la méthode statique, on se satisfait généralement d'un très simple this.counter=(this.counter||0)+1;, ya pas 50000variables statiques.

    Cela dit on peut très bien comme il a été remarqué se servir du nom du constructeur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    function A(){
     A.staticVar=(A.staticVar||0)+1;
    }
    var a = new A();
    var b = new A();
    Le self, c'est bon pour php et java
    en C++ on se sert du nom de classe ou namespace, c'est tres bien.

    Sinon, j'ai vu un arguments.callee qui trainait, on peut jouer dessus.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
       function A() {
         arguments.callee['stat']=(arguments.callee['stat']||0)+1;
       };
    var result = A();
    console.log(A.stat);
    var result = A();
    console.log(A.stat);
    cela dit, je pense qu'on se fourvoit en essayant de se ramener à d'autres langages.

  14. #34
    Membre expérimenté Avatar de Willpower
    Homme Profil pro
    sans emploi
    Inscrit en
    Décembre 2010
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : sans emploi

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 009
    Points : 1 519
    Points
    1 519
    Par défaut
    Citation Envoyé par galerien69 Voir le message
    Oui, c'est pas de l'héritage à proprement parler, mais s'en est tout comme. La différence, c'est que l'appelant externe n'a accès qu'à la méthode de premier niveau ou alors[..]
    En fait, l'héritage se décompense en 2 catégories différente lorsque B hérite de A, alors soit "B is A" soit "B has A".

    Dans ton exemple la première catégorie n'existe plus puisque tu fais un second objet A distinct du this de B.

    Citation Envoyé par galerien69 Voir le message
    c'est la même chose que faire un new en fait (vu qu'on construit).
    Ca revient donc à faire un encapsulant qui donne qqch dustyle
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    var myA = classes.New(A, args);
    classes.New = function(A, args){
     var a = new A(args);
     a.__construct(args);//avec construction différée.
     return a;
    }
    S'il n'avait pas envie de mofidier les fonctions, j'ai supposé qu'il n'avait non plus pas envie de modifier tous les appels à ces fonctions.

    Or ta méthode impose de connaître le nombre d'arguments (1 dans ton exemple) de chaque méthode. D'où l'appel à la méthode "apply" dans ma version. (qui est assez contrainiente avec les "new", d'où la longueur de mon code.)

    Citation Envoyé par galerien69 Voir le message
    Sinon, j'ai vu un arguments.callee qui trainait, on peut jouer dessus.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
       function A() {
         arguments.callee['stat']=(arguments.callee['stat']||0)+1;
       };
    heu pas trop ...
    m'étonnerait qu'il n'utilise son "static" uniquement dans le constructeur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    function A(){
      this.getStatic = function(){alert("arguments.callee != A :"+arguments.callee != A);};
    }
    Citation Envoyé par galerien69 Voir le message
    cela dit, je pense qu'on se fourvoit en essayant de se ramener à d'autres langages.
    Je pense qu'on est tout à fait d'accord là dessus et que fanfouer aurait intérêt à refaire une nouvelle version même si ça prend plus de temps que d'essayer de recoller une vielle qui le fera tomber dans un casse-tête à la première tentative de mise à jour.

  15. #35
    Membre régulier
    Profil pro
    Étudiant
    Inscrit en
    Janvier 2008
    Messages
    253
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2008
    Messages : 253
    Points : 84
    Points
    84
    Par défaut
    Bonjour à vous deux.

    Je prendrais sans hésiter le code de Willpower avec le this.constructor, ca colle parfaitement à mes besoins.

    Citation Envoyé par Willpower Voir le message
    Je pense qu'on est tout à fait d'accord là dessus et que fanfouer aurait intérêt à refaire une nouvelle version même si ça prend plus de temps que d'essayer de recoller une vielle qui le fera tomber dans un casse-tête à la première tentative de mise à jour.
    Je suis d'accord avec vous et de prime à bord je serais tenté de dire qu'on doit se soumettre aux spécificités les plus fines du langage choisi pour en tirer tous les bénéfices.
    Mais d'un autre côté je suis seul à gérer ce projet, je ne peux pas me permettre d'avoir deux structures pour une même chaîne de traitement.

    Je passerai sur des choses comme le foreach par exemple qu'on ne trouve pas en JS mais qu'on peut reproduire avec jQuery entres autres.
    Par contre sur des choses comme le nom des classes, la signature des méthodes et la portée des membres, je me sens forcé d'avoir les mêmes partout pour ne pas passer à côté de quelque chose plus tard. C'est uniquement dans ce but que je cherche à avoir les éléments basiques de la POO comme l'héritage et l'appel à self() ou parent (), pas par étroitesse d'esprit.

    Dans un contexte objet voila ce que je retiendrai comme code, je doute qu'il soit aisé de se passer du nom de la classe dans un autre contexte :
    Code javascript : 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
     
    Function.prototype.self = function(){
    	return this.constructor;
    }
    Function.prototype.extends = function(){
    	var FN = this;
     
    	var extends = function(FN,parent){	
    		/*if(arguments.length>2){
    			parent = inherits.apply(this,[].slice.call(arguments,1));
    		}*/
     
    		var newFN = function(){
    			parent.apply(this,arguments);
    			this._super = this._super ? {_super:this._super} : {};
    			for(var i in this){
    				if(typeof this[i] == "function"){
    					this.super[i] = this[i];//(function(obj,fnName){ return function(){ return obj[fnName].apply(this,arguments); }; })(this,i);
    				}
    			}
    			return FN.apply(this,arguments);
    		};
     
    		var proto = function(){};
    		proto.prototype = parent.prototype;
    		newFN.prototype = new proto();
     
    		for(var i in FN.prototype){
    			newFN.prototype[i] = FN.prototype[i];
    		}
    		newFN._super = parent;
    		return newFN;
    	};
     
    	self().__PARENT = argument[0];
     
    	return extends.apply(window,[this].concat([].slice.call(arguments,0)));
    };
    Function.prototype.parent = function(){
    	return self().__PARENT;
    }
    J'ai "désactivé" l'héritage multiple pour pouvoir mettre en place plus facilement l'accès au parent. De toutes façons il n'y a pas d'héritage multiple en PHP, Java ou ActionScript - autres langages utilisés - donc ça ne me gêne pas de ne pas l'avoir.

    Qu'en pensent les pros?

  16. #36
    Invité
    Invité(e)
    Par défaut
    S'il n'avait pas envie de mofidier les fonctions, j'ai supposé qu'il n'avait non plus pas envie de modifier tous les appels à ces fonctions.
    Je vois l'idée. Pour moi c'était simplement d'éviter la dupplication de la ligne de code __construct.

    Or ta méthode impose de connaître le nombre d'arguments (1 dans ton exemple) de chaque méthode. D'où l'appel à la méthode "apply" dans ma version. (qui est assez contrainiente avec les "new", d'où la longueur de mon code.)
    oui enfin bon, si ya un constructeur différé, c'est pour lui passer les args correct le moment voulu donc l'instance a déjà été créé. Un apply où call (celui qui prend un tableau) est donc facilement faisable.
    Cela dit, je suis d'accord que ta méthode est plus générique. Je lui reprochais surtout le fait d'être un espèce de script qui parcours les classes courantes. La syntaxe que je propose est juste une alternative (contraignante nécessitant limplem de construct) se passant de prototype.
    On appèle New et basta. Dans la précédente il faut définir un tableau des noms dont on veut des instances

    heu pas trop ...
    m'étonnerait qu'il n'utilise son "static" uniquement dans le constructeur :
    oui.

    edit : j'ai oublié l'héritage
    En fait, l'héritage se décompense en 2 catégories différente lorsque B hérite de A, alors soit "B is A" soit "B has A".

    Dans ton exemple la première catégorie n'existe plus puisque tu fais un second objet A distinct du this de B.
    En fait, non. L'objet que B retourne est bien l'instance crée par A...qu'on aggrémente de ce qu'on veut.
    Et on appèle pas le mot clé new, le mot clé this, n'a aucun rôle à jouer.

  17. #37
    Membre expérimenté Avatar de Willpower
    Homme Profil pro
    sans emploi
    Inscrit en
    Décembre 2010
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : sans emploi

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 009
    Points : 1 519
    Points
    1 519
    Par défaut
    @galerien69: pour ce qui n'est plus vraiment de l'héritage, je faisais donc référence à ton post #19

    ceci plus précisément :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function A(param){
    	var obj={};
            //update param
            obj.perso='lol';
    	obj.protected = function(){ alert("protected"); };
    	return obj;
    }
    function B(){
      var myA = A({});
      myA.newMethod="lol";
      return myA;
    }
    Effectivement après relecture B renvoie bien un nouvel objet "A" surchargé, par contre tu perds les prototypes de B (s'il en avait) et l'objet retourné ne répondra donc pas positif au "obj instanceof B".

  18. #38
    Membre expérimenté Avatar de Willpower
    Homme Profil pro
    sans emploi
    Inscrit en
    Décembre 2010
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : sans emploi

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 009
    Points : 1 519
    Points
    1 519
    Par défaut
    Citation Envoyé par fanfouer Voir le message
    Bonjour à vous deux.

    Je prendrais sans hésiter le code de Willpower avec le this.constructor, ca colle parfaitement à mes besoins.


    Je suis d'accord avec vous et de prime à bord je serais tenté de dire qu'on doit se soumettre aux spécificités les plus fines du langage choisi pour en tirer tous les bénéfices.
    Mais d'un autre côté je suis seul à gérer ce projet, je ne peux pas me permettre d'avoir deux structures pour une même chaîne de traitement.

    Je passerai sur des choses comme le foreach par exemple qu'on ne trouve pas en JS mais qu'on peut reproduire avec jQuery entres autres.
    Par contre sur des choses comme le nom des classes, la signature des méthodes et la portée des membres, je me sens forcé d'avoir les mêmes partout pour ne pas passer à côté de quelque chose plus tard. C'est uniquement dans ce but que je cherche à avoir les éléments basiques de la POO comme l'héritage et l'appel à self() ou parent (), pas par étroitesse d'esprit.

    Dans un contexte objet voila ce que je retiendrai comme code, je doute qu'il soit aisé de se passer du nom de la classe dans un autre contexte :
    Code javascript : 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
     
    Function.prototype.self = function(){
    	return this.constructor;
    }
    Function.prototype.extends = function(){
    	var FN = this;
     
    	var extends = function(FN,parent){	
    		/*if(arguments.length>2){
    			parent = inherits.apply(this,[].slice.call(arguments,1));
    		}*/
     
    		var newFN = function(){
    			parent.apply(this,arguments);
    			this._super = this._super ? {_super:this._super} : {};
    			for(var i in this){
    				if(typeof this[i] == "function"){
    					this.super[i] = this[i];//(function(obj,fnName){ return function(){ return obj[fnName].apply(this,arguments); }; })(this,i);
    				}
    			}
    			return FN.apply(this,arguments);
    		};
     
    		var proto = function(){};
    		proto.prototype = parent.prototype;
    		newFN.prototype = new proto();
     
    		for(var i in FN.prototype){
    			newFN.prototype[i] = FN.prototype[i];
    		}
    		newFN._super = parent;
    		return newFN;
    	};
     
    	self().__PARENT = argument[0];
     
    	return extends.apply(window,[this].concat([].slice.call(arguments,0)));
    };
    Function.prototype.parent = function(){
    	return self().__PARENT;
    }
    J'ai "désactivé" l'héritage multiple pour pouvoir mettre en place plus facilement l'accès au parent. De toutes façons il n'y a pas d'héritage multiple en PHP, Java ou ActionScript - autres langages utilisés - donc ça ne me gêne pas de ne pas l'avoir.

    Qu'en pensent les pros?
    Je vois que t'as essayé de reprendre ma version que j'avais divisé 2 versions (prototype et function) en la recollant en un prototype. C'est plus ou moins correct par contre il y a toute une partie inutile. (cette version est beaucoup plus légère) :

    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
    Function.prototype.extends = function(FN,parent){	
    		var FN = this;
    		var newFN = function(){
    			parent.apply(this,arguments);
    			this._super = this._super ? {_super:this._super} : {};
    			for(var i in this){
    				if(typeof this[i] == "function"){
    					this.super[i] = this[i];
    				}
    			}
    			return FN.apply(this,arguments);
    		};
     
    		var proto = function(){};
    		proto.prototype = parent.prototype;
    		newFN.prototype = new proto();
     
    		for(var i in FN.prototype){
    			newFN.prototype[i] = FN.prototype[i];
    		}
     
    		newFN.__PARENT = parent;
    		return newFN;
    };
    Function.prototype.parent = function(){
    	// retourne la classe parente de la classe(fonction/constructeur)
    	return this.__PARENT;
    }
    Object.prototype.self = function(){
    	// retourne la classe(constructeur) de l'objet
    	return this.constructor;
    }
    Object.prototype.parent = function(){
    	// retourne la classe parente de la classe(constructeur) de l'objet
    	return this.self().parent();
    }
    J'ai un peu modifié tes prototype parent/self, j'ai l'impression que tu confonds les "Function" et les "Objet", mais rassure-toi c'est normal de s'y perdre en javascript lorsque l'on est habitué aux autres langages.

  19. #39
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2009
    Messages
    354
    Détails du profil
    Informations personnelles :
    Localisation : France, Sarthe (Pays de la Loire)

    Informations forums :
    Inscription : Février 2009
    Messages : 354
    Points : 491
    Points
    491
    Par défaut
    A javascript et la POO par classe !

    Concernant l'invocation des méthode overrider et constructeur parent, y'a deux méthodes possible, l'une en encapsulant l'appel originel appelant la méthode parent, pour référencer la méthode parent, ce que fait jQuery...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    //depuis une fonction dédié, comme inherit
    for(var i in proto){
        //test si il existe l'invocation de super dans la méthode
        if(callSuper){
            var originalFn = proto[i];
            proto[i] = function(){
                this._super = function(){
                    parent.prototype[i].apply(this, arguments);
                };
                originalFn.apply(this, arguments);
            };
        }
    }
    La seconde méthode est de passer par l'objet arguments et sa propriété calle, ce que fait dojo.

    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
     
    for(var i in proto){
        //si c'est une fonction
        if(isFn){
            var fn = proto[i];
            fn.name = i;
            fn.parent = parent; //le prototype parent si il existe
        }
    }
    //la fonction super
    proto.callSuper = function(args){
        var caller = args.callee,
        fnArgs = Array.prototype.slice.call(arguments, 1);
        return caller.parent[caller.name].apply(this, fnArgs);
    }
    //puis dans la classe une fonction
    maFn : function(a1, a2){
        this.callSuper(arguments, a1, a2);
    }

    Pour l'encapsulation c'est plus compliqué. Soit on se limite a des varibles privé mais static, via l'encapsulation de la définition de la classe dans un scope dédié

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    maClasse = (function(){
        var priver = "ok";
        var constructuer = function(){
             //utilise priver
        }
        constructuer .prototype = {
        //utilise priver
        }:
         return constructuer ;
    })();
    Soit on passe par un constructeur définissant des closures, ce qui a mon sens n'est pas super niveau des perfs, et de la maintenance a moins d'oublier de prototyper

    Ou alors de passer par une fonction private, inclue dans le prototype. Mais seule les fonctions pourront être privée.

    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
    //depuis une fonction dédié, comme inherit
     
    for(var i in proto){
        //si c'est une fonction privé, on vérifie que l'appel a été éffctué par la fonction callPrivate
        if(isPrivate){
            var originalFn = proto[i];
            proto[i] = function(){
                if(arguments.callee.caller == this.callPrivate)
                    return originalFn.apply(this, arguments);
            };
            proto[i].name = i;
        }
    }
    proto.callPrivate = function(property){
        //on récupère la fonction ayant appeller getPrivate
        var caller = arguments.callee.caller.caller;
        if(caller && caller == proto[caller[name]]){
            return this[property].apply(this, arguments);
        }
    }
    j'ai jamais testé la dernière solution, de plus caller est déprécié, mais tourne sous tout les browser.

    Pour ce qui est des variables static et self, comme en php.
    Pour self, rien de plus simple, il suffit de référencer le constructeur
    Pour static, il faut là aussi utiliser l'objet argument et la propriété callee, en ayant pris soit de référencer comme propriété de la fonction appelante le constructeur d'origine....

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    //depuis une fonction dédié, comme inherit
    for(var i in proto){
        //si c'est une fonction
        if(isFn){
            var fn= proto[i];
            fn.origineConstructeur = constructeur
        }
    }
    proto.getStatic= function(property){
        //on récupère la fonction ayant appeller getStatic
        var caller = arguments.callee.caller;
        return caller.origineConstructeur[property];
    }
    Tout ces exemples sont "brute de force" , y'a sans doute des erreur, c'est juste pour expliquer le truc

  20. #40
    Membre régulier
    Profil pro
    Étudiant
    Inscrit en
    Janvier 2008
    Messages
    253
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2008
    Messages : 253
    Points : 84
    Points
    84
    Par défaut
    Citation Envoyé par Willpower Voir le message
    Je vois que t'as essayé de reprendre ma version que j'avais divisé 2 versions (prototype et function) en la recollant en un prototype. C'est plus ou moins correct par contre il y a toute une partie inutile. (cette version est beaucoup plus légère)
    Oui, en effet, je voulais éviter que la fonction extends/inherits globale se balade et provoque des incompatibilité avec on ne sait trop quel code.

    J'ai un peu modifié tes prototype parent/self, j'ai l'impression que tu confonds les "Function" et les "Objet", mais rassure-toi c'est normal de s'y perdre en javascript lorsque l'on est habitué aux autres langages.
    Oui, je confond un peu les deux d'où ma demande d'intégrer la méthode __construct déjà au sein du constructeur lui-même.

    En outre, pensez-vous que l'on peut transposer self() et parent() dans un contexte hors-objet?
    Car pour l'instant je peux uniquement les appeler depuis une méthode d'instance mais surement pas une méthode de classe je crois (il y a this devant).
    Ca pourrait être pas mal de pouvoir accéder de cette façon aux membres statiques depuis une méthode elle-même statique non?

    J'ai un exemple illustrant mon besoin : j'ai 3 classes A, B et C. B étend A et C étend B.
    Dans chaque classe je déclare un tableau statique contenant une liste de choses et je complète cette liste au fur et à mesure que je descends dans la hiérarchie.
    Je déclare donc une méthode statique qui va chercher la liste du parent et qui copie le contenu dans la liste de la classe fille. Ensuite on ajoute les données propre à la classe.

    Mais dans le but de ne pas recopier cette méthode (qui est toujours la même au ; près) j'aimerai la déclarer dans la classe au sommet de la hiérarchie et m'en servir dans tous ses descendant. Pour cela j'ai besoin de faire des références relatives au parent et à la classe fille sans utiliser les noms des classes.

    Ca pourrait donner ça :
    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
     
    MaClasse = function(){
     //...
    }
     
    MaClasse._data = new Object(); // Tableau associatif.
     
    MaClasse.init = function(){
       if (parent() != null){
           self()._data = $.extend(true, parent()._data, self()._data);
       }
    }
     
    MaClasse.init();
     
    Fille = function(){
       //....
    }
     
    Fille._data = {...};
     
    Fille.init();

+ Répondre à la discussion
Cette discussion est résolue.
Page 2 sur 4 PremièrePremière 1234 DernièreDernière

Discussions similaires

  1. Implémentation Runnable et héritage
    Par abdelilah dans le forum Débuter avec Java
    Réponses: 1
    Dernier message: 04/03/2010, 02h11
  2. Réponses: 8
    Dernier message: 10/11/2009, 22h41
  3. Héritage et d'appel de méthode
    Par Sunsawe dans le forum Langage
    Réponses: 11
    Dernier message: 31/07/2009, 00h08
  4. Réponses: 7
    Dernier message: 24/09/2008, 12h18
  5. Héritage : problème d'appel de méthodes
    Par parano dans le forum C++
    Réponses: 15
    Dernier message: 02/03/2007, 15h42

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