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. #41
    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
    MaClasse est un constructeur d'objet ?

    Dans ton exemple, quand tu fais MaClasse.init() tu veux initialiser quoi ? Un objet non? Donc ça ne serait pas plutôt :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    MaClasse = function(){
     //...
    }
     
    var obj = new MaClasse();
    obj.init();
    Et si oui, j'aurai une 2ème question avant de te proposer une solution :
    Le "MaClasse._data" est un tableau partagé pour TOUS les objets générés par MaClasse, ou il faut un tableau par objet ? S'il faut un tableau par objet alors tu dois prototyper :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MaClasse.prototype._data = new Object(); // Tableau associatif.

    nb: "{}" est identique à "new Object()" et plus simple à écrire.

  2. #42
    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
    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.
    La réponse est oui, tu peux faire hériter les membres statique . Pour cela Il suffit de recopier les membre direct (ne descendant pas de l'objet Function) de l'objet constructeur de la classe parent dans le constructeur de la classe fille.

    function inherit(proto, parent){
    ...
    for(var i in parent){
    if(parent.hasOwnProperty(i))
    constrcuteur[i] = parent[i];
    }
    }
    Par contre il te faudra sans doute des mutateurs sur ces membres, pour qu'ils puissent être mise a jour dans las classe filles a chaque modification, ou nouvelle ajout.

    Pour la liste, et si tu veux que ces listes soit lié, personnellement je passerait non pas par un tableau (quoi que....) mais par des objets chainé par leurs prototypes !
    Suffit juste de faire une fonction Singleton, qui fait la même chose que extends ou inherit, mais qui renvoie une instance !

  3. #43
    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
    MaClasse est un constructeur d'objet ?

    Dans ton exemple, quand tu fais MaClasse.init() tu veux initialiser quoi ? Un objet non?
    Oui c'est un constructeur mais init() étant ici une méthode statique, je veux "initialiser la classe". C'est l'équivalent de l'initialisation statique en Java :

    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    class Classe {
     
    static {
     // Instructions d'initialisation de la classe executé lors de l'import de la classe (et non lors de la construction d'un objet).
    }
     
    //...
    }

    Bon je concède que je pourrais mettre mes instructions à la suite de la déclaration de la classe mais je souhaite que ma méthode init() soit transposable à tous les enfant comme je le disais dans mon précédent post.

    Le "MaClasse._data" est un tableau partagé pour TOUS les objets générés par MaClasse, ou il faut un tableau par objet ?
    C'est un tableau partagé par tous les objets de la classe MaClasse.

    nb: "{}" est identique à "new Object()" et plus simple à écrire.
    C'est vrai

    Citation Envoyé par kimjoa Voir le message
    La réponse est oui, tu peux faire hériter les membres statique . Pour cela Il suffit de recopier les membre direct (ne descendant pas de l'objet Function) de l'objet constructeur de la classe parent dans le constructeur de la classe fille.
    Oui mais si on fait "hériter les membres statiques", on va se retrouver avec une seule liste pour toute la hiérarchie.
    Pour moi, chaque niveau à sa propre liste, même si à l'initialisation de la classe on déverse le contenu de la liste parent dans celle de l'enfant.

    Je prendrai le temps de faire un petit résumé en fin de topic vu la multiplicité des problèmes évoqués, merci à vous tous

  4. #44
    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
    Une version complète avec "init" déclaré uniquement sur la classe "MaClasse" qui est ensuite "hérité" par "Fille".

    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
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    Function.prototype.extends = function(parent){		
    		var FN = this;
    		if(arguments.length>1)
    			parent = Function.prototype.extends.apply(parent,[].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];
    				}
    			}
    			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];
    		}
     
    		// copie des statiques parents
    		for(var i in parent){
    			newFN[i] = parent[i];
    		}
    		// copie(+ecrase) des statiques nouveau
    		for(var i in FN){
    			newFN[i] = FN[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();
    }
     
     
    // classe mère
    function MaClasse(){
       //....
    }
    MaClasse._data = {};
    MaClasse.init = function(){
    	var Class = this;
    	if(Class.parent())
    		;//Class._data = $.extend(true, Class.parent()._data, Class._data);
    };
    MaClasse.init();
    // classe fille
    function Fille(){
       //....
    }
    Fille = Fille.extends(MaClasse);
    Fille._data = {};
    Fille.init();
    nb: j'ai remis la ligne des appels récursifs d'héritage puisque dans le poste précédent tu parlais d'une classe B héritant de A et de C héritant de B.

    Exemple d'utilisation :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    C = C.extends(B,A); // C enfant de (B enfant de A)

  5. #45
    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
    C'est exactement ça dont j'ai besoin, merci

    Que la méthode init soit déclarée dans le prototype de Function ou dans la classe mère ne change pas grand chose dans ce cas-ci mais si on la déclare dans le prototype de Function, on peut reproduire sans peine l'init statique des classes Java, un bonus.

    En effet je viens de me rappeler que this ne représente pas forcément l'instance en javascript mais se rapporte plus au scope.
    Ca deviens de plus en plus clair

    Par contre le dernier code :
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    C = C.extends(B,A); // C enfant de (B enfant de A)
    Ca voudrait plutôt dire que C hérite de A et B (on oublie le B étend A).

    Pour avoir B étend A et C étend B, j'écrirai plutot :
    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
     
     
    var A = function(){
     
    }
     
    var B = function(){
     
    }
    B.extends(A);
     
    var C = function(){
     
    }
    C.extends(B);
    En l'écrivant je me suis rendu compte que c'était équivalent pour C, mais au niveau de la représentation arborescente c'est pas exactement la même chose.

    Encore merci

  6. #46
    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
    Oui mais si on fait "hériter les membres statiques", on va se retrouver avec une seule liste pour toute la hiérarchie.
    Pour moi, chaque niveau à sa propre liste, même si à l'initialisation de la classe on déverse le contenu de la liste parent dans celle de l'enfant.
    Ok, je comprends mieux pourquoi tu cherches à introduire une méthode d’initialisation de la classe, à la manier du static de java.
    Rien ne t'en empêche !! Par exemple une méthode de callback passé en dernier arguments de la fonction extends appelé sur le contexte du constructeur

    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
     
    function Singleton(proto, parent){
        var inherit = function(){};
        var proto = parent instanceOf Function ?  parent.prototype : parent || {};
        inherit.prototype = proto;
        var object = new inherit();
       for(var i in proto){
           object[i] = proto[i];
       }
       return object;
    }
    /**
    * proto -> un object , contenant les propriété du prototype ainsi que son constructeur
    parent -> soit un objet , soit une fonction .... on étends des objets en js pas des classes ;)
    */
    function Class(proto, parent, callback){
         //héritage en javascript
        var constructeur = proto.constructeur == Object ? function(){} : protot.constructor;
        var inherit = Singleton(proto, parent);
        constructeur.prototype = inherit;
        constructeur.prototype.constructor = constructeur;//bug ie 6 ou 7
     
      //traitement spécifique (membre static, private, méthode super, self, static ect .......)
        ....
        //appel du callback d'initialisation
        if(callback)
             callback.call(constructeur, parent);
    }
    brute de force encore.
    A partir de ces méthodes, et si tu veux des listes static liée ...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var A = new Class({
            constructor : function(){...},
            'static membreStatic' : "",
            'static listeStatic' : {}
        }, null, null);
     
        var B = new Class({
            constructor : function(){...},
            'static membreStatic' : "overrider",
            'static listeStatic' : new Singelton({}, A.listeStatic)
        }, A, function(){...});
     ect....
    note : En js l'héritage de classe native comme Array pause problème, car les constructeur ne sont pas vraiment public et accessible. On ne peux pas faire par exemple pour initialiser une liste hérité de Array

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Array.call(pseudoListe);
    Ca marchera pas .....
    C'est pour cela que dans l'exemple, listeStatic est un objet
    Si tu veux plus de renseignement tu trouvera plein d'exemple et de hack, pour le faire sur le net, mais c'est du bidouillage mais tu pourra peux être t'en suffire

    Je prendrai le temps de faire un petit résumé en fin de topic vu la multiplicité des problèmes évoqués, merci à vous tous
    Bon courage

  7. #47
    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 kimjoa Voir le message
    Bon courage
    +1

    même moi je suis complètement largué dans ce sujet.

  8. #48
    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 kimjoa Voir le message
    Rien ne t'en empêche !! Par exemple une méthode de callback passé en dernier arguments de la fonction extends appelé sur le contexte du constructeur.
    Oui rien ne m'en empêche mais après réflexion et comme cela a été dit plus haut : on ne peut pas modifier le jeu d'instructions d'une fonction préalablement déclarée.

    Fort de ce constat, le gain induit par le passage par la fonction d'héritage est lourdement limité puisqu'on est tout de même obligé de laisser une ligne au bas de la déclaration d'une classe qui n'est pas forcée d'hériter d'un parent.

    Je préfère donc éviter de surcharger la pile d'appel et laisser une ".init();" au bas de chaque classe qui possédera une init statique.

    Cependant, ta méthode était bien évidemment valable

    note : En js l'héritage de classe native comme Array pause problème, car les constructeur ne sont pas vraiment public et accessible. On ne peux pas faire par exemple pour initialiser une liste hérité de Array
    C'est pour ça que je complète directement le prototype.
    Parenthèse à part, j'utilise depuis un certain temps la librairie phpjs qui rend disponible certaines fonctions de l'API PHP recordée en JS. Ça me fera encore plus gagné de temps pour le transcodage PHP -> JS.

    Si tu veux plus de renseignement tu trouvera plein d'exemple et de hack, pour le faire sur le net, mais c'est du bidouillage mais tu pourra peux être t'en suffire
    Pour ce qui est des hacks je m'en méfie.
    Même si mon but est ici de gagner du temps en évitant d'éparpiller mes comportements suivant le langage, ça reste sur des sentiers balisés.
    Javascript étant surtout du côté client (là on ne maîtrise pas le rythme de mise à jour), il n'est pas acceptable de se retrouver avec des sites caduques lors de chaque mise à jour du navigateur.

    Avant de laisser un code un peu finalisé, j'ai eu l'occasion de tester réellement le code de willpower et la completion du prototype d'Object créée des erreurs sur jQuery core et UI ainsi que Google Maps V3 (c'est même rapporté par firebug qui me dit de me méfier).
    Est-ce que cette portion de code est réellement obligatoire pour self/parent?
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    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();
    }

  9. #49
    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
    Sinon as-tu essayé des converter de code jav to javascript ?

  10. #50
    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
    Non pas encore et je ne sais pas si ça arrivera.

    En fait le gros du projet est composé de plusieurs librairies d'abord écrites en PHP, langage dans lequel j'ai fait quasiment 80% du travail.
    Le jeu étant maintenant de porter toutes les classes vers des langages client pour ne plus faire de différences entre serveur et client (en gros et pas dans tous les cas mais c'est une longue histoire).

    Donc la conversion interviendra progressivement PHP -> JS, PHP -> Java, PHP -> ActionScript et peut-etre PHP -> C++ (mais là j'ai pas encore étudié la question).

    Tout dépend en fait du langage utilisé en premier.

  11. #51
    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 rien ne m'en empêche mais après réflexion et comme cela a été dit plus haut : on ne peut pas modifier le jeu d'instructions d'une fonction préalablement déclarée.

    Fort de ce constat, le gain induit par le passage par la fonction d'héritage est lourdement limité puisqu'on est tout de même obligé de laisser une ligne au bas de la déclaration d'une classe qui n'est pas forcée d'hériter d'un parent.

    Je préfère donc éviter de surcharger la pile d'appel et laisser une ".init();" au bas de chaque classe qui possédera une init statique.

    Cependant, ta méthode était bien évidemment valable


    C'est pour ça que je complète directement le prototype.
    Parenthèse à part, j'utilise depuis un certain temps la librairie phpjs qui rend disponible certaines fonctions de l'API PHP recordée en JS. Ça me fera encore plus gagné de temps pour le transcodage PHP -> JS.


    Pour ce qui est des hacks je m'en méfie.
    Même si mon but est ici de gagner du temps en évitant d'éparpiller mes comportements suivant le langage, ça reste sur des sentiers balisés.
    Javascript étant surtout du côté client (là on ne maîtrise pas le rythme de mise à jour), il n'est pas acceptable de se retrouver avec des sites caduques lors de chaque mise à jour du navigateur.

    Avant de laisser un code un peu finalisé, j'ai eu l'occasion de tester réellement le code de willpower et la completion du prototype d'Object créée des erreurs sur jQuery core et UI ainsi que Google Maps V3 (c'est même rapporté par firebug qui me dit de me méfier).
    Est-ce que cette portion de code est réellement obligatoire pour self/parent?
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    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();
    }
    Effectivement, il vaut mieux éviter la surcharge d'objets surtout que tu utilises des librairies.

    Donc soit 2 possibilité :

    MaClasse.prototype.self = .... // ne produira une fonction self que pour les objets générés par "MaClasse" (et ses héritiers si l'héritage est bien fait).

    Autrement une function plutôt qu'un prototype :

    function self(obj){
    return this.constructor;
    }

    appelé de cette façon "self(this)" .... mais bon, autant ne pas écrire de fonction et utiliser "this.constructor" ^^

  12. #52
    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
    appelé de cette façon "self(this)" .... mais bon, autant ne pas écrire de fonction et utiliser "this.constructor" ^^
    Oui ça ne sert plus à grand chose, hormis pour la sémantique.
    C'est bien dommage qu'on ne puisse pas le faire proprement en tout cas.

  13. #53
    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
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    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();
    }
    Faut éviter de surcharger Object pour des raisons de compatibilité entre frameworks.
    Sinon la fonction parent() est fausse, elle engendra une erreur de récursivité.

  14. #54
    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 kimjoa Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    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();
    }
    Faut éviter de surcharger Object pour des raisons de compatibilité entre frameworks.
    Sinon la fonction parent() est fausse, elle engendra une erreur de récursivité.
    Non car Function.prototype.parent != Object.prototype.parent et "constructor" sera d'abord interprété comme une "Function". D'ailleurs le code suivant fonctionne :

    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
    Function.prototype.parent = function(){
    	// retourne la classe parente de la classe(fonction/constructeur)
    	alert("function parent");
    	//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();
    }
    function A(){};
    var a = new A();
    a.parent();
    nb: en fait, c'est fanfouer qui n'a "quoté/cité" que 2 des fonctions, c'est sans doute pour ça que ça a prété à confusion.

  15. #55
    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
    Bonsoir!

    Je me permets de relancer ce topic parce que je pense avoir eu de l'inspiration mais un tout petit soucis persiste

    Désolé au passage pour la période de relâchement, j'ai été bien occupé ce début de mois et je n'ai poursuivi ma recherche que récemment.

    J'ai apporté quelques modifications au code de Willpower et j'arrive à exécuter une méthode à la construction de l'objet (du style __construct()) sans avoir à la spécifier en bas de classe.
    En fait le problème de base était que lorsque j'appelais le constructeur Javascript de la classe, tous étaient exécutés (ceux des parents comme celui de l'enfant) et si l'appel à __construct était spécifié au bas de chaque, on appelait successivement chaque constructeur avec la même signature que celui de l'enfant! Or Ils n'ont pas tous la même signature.

    D'ou ce code-ci, commenté :
    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
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
     
    var CLASS_BUILD_INSTANCE = false;
    Function.prototype.extends = function(parent){	
    	var FN = this;
    	// Si il y a plusieurs classes passées en paramètres, on récupère seuelement la premiere (pas d'héritage multiple)
    	if(arguments.length > 1){
    		parent = Function.prototype.extends.apply(parent,[].slice.call(arguments,1));
    	}
     
    	// Création d'un nouveau constructeur
    	var newFN = function(){
    		alert ("Constructeur!!!!!");
    		var fnTest = /xyz/.test(function(){xyz;}) ? /\b__super\b/ : /.*/;
     
    		var top = false; // Flag - Si on est en présence d'une feuille de l'arbre
    		if (!CLASS_BUILD_INSTANCE){
    			CLASS_BUILD_INSTANCE = true;
    			var top = true;
    		}
     
    		parent.apply(this, arguments); // Build du parent (execution de cette methode newFN récursivement sur les parents).
     
    		// Itération sur chaque membre pour ajouter quelques "special POO features"
    		for(var i in this){
    			// Liaison dynamique à l'éxecution d'une méthode __super (Inspiré du code de John Resig).
    			var parent_fn = parent[i]; // Méthode du parent
    			var actual_fn = this[i]; // Méthode de l'objet
     
    			if (typeof actual_fn == "function" && typeof parent_fn == "function" && fnTest.test(actual_fn)){ // Si on a bien deux fonctions
    				alert ("La propriété "+i+" mérite un __super");
    				this[i] = (function(obj, name, fn, pfn){ 
    				alert ("Execution!!!!!");
    					// Nouvelle fonction
    					return function() {
    						var tmp = obj.__super; // on enregistre ce qui est contenu dans __super avant toute chose
     
    						// On ajoute ensuite une méthode __super à l'objet qui correspond à la méthode du parent.
    						obj.__super = pfn;
     
    						// La méthode originale est ensuite executée
    						var ret = fn.apply(obj, arguments);
     
    						obj.__super = tmp; // On rétablit l'ancienne valeur de l'attribut __super
     
    						return ret;
    					};
    				})(this, i, actual_fn, parent_fn);
    			}
    		}
     
    		var result = FN.apply(this,arguments); // Build de l'objet en lui-même.
     
    		// Execution du constructeur si on construit le premier niveau de classe (la classe d'instance quoi)
    		if (top){
    			this.__construct.apply(this,arguments);
    			CLASS_BUILD_INSTANCE = false;
    		}
     
    		return result;
    	};
     
    	// Extension (copie membre à membre)
    		var proto = function(){};
    		proto.prototype = parent.prototype;
    		newFN.prototype = new proto();
     
    		for(var i in FN.prototype){
    			newFN.prototype[i] = FN.prototype[i];
    		}
     
    		// copie des statiques parents
    		for(var i in parent){
    			newFN[i] = parent[i];
    		}
     
    		// copie(+ecrase) des statiques nouveau
    		for(var i in FN){
    			newFN[i] = FN[i];
    		}
     
    	// Spécification du parent.
    		newFN.__PARENT = parent;
     
    	return newFN;
    };
    J'ai vérifié, __construct est bien appelé au "new" en ayant enlevé l'appel en bas de classe.
    Vu qu'en parallèle j'ai fixé cette exécution du "__construct" uniquement pour la classe enfant, il faut appeler les __construct des parents (qui peuvent donc avoir des signatures différentes) avec l'aide de __super.
    Dans de précédents posts, je crois qu'on était arrivé à la conclusion qu'il n'était pas possible d'ajouter un __super dans chaque méthode mais je crois que John Résig m'a aidé sur ce point.

    Mais ce que j'ai écris n'a pas l'air de fonctionner. L'itération sur les membres de this se fait bien, mais à l’exécution, this.__super est systématiquement "undefined" dans toutes les méthodes.
    Pourtant il me semble réaliser le bind de la closure de John Resig correctement.
    A noter également que lors de l'appel d'une quelconque méthode, le alert ("Execution!!!!!"); n'est même pas activé.

    Est-ce que l'un d'entre-vous aurait une solution? J'ai vraiment l'impression de toucher au but et si j'arrive à avoir __super ce serait vraiment... super (!), ne serait-ce que pour appeler mes constructeurs en cascade.

    Merci par avance pour ce dernier effort.

  16. #56
    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
    Bien j'ai trouvé un début de piste : j'ai compris pourquoi la closure qui ajoute __super dans le contexte de la méthode à exécuter n'était pas appelée.

    Lors du listage des propriétés de l'objet courant, on regarde si la méthode en question est également une méthode dans le parent (normal sinon il n'y aurait pas lieu d’appeler __super). Or le parent étend potentiellement une autre classe et du coup il contient lui aussi une référence à une fonction "newFN" (quand on utilise toSource() sur le parent, on retrouve le code d'une fonction newFN sans la liste des attributs et des méthodes qui le caractérisent).
    Il faut donc fournir à newFN la liste correcte des méthodes du parent pour qu'elle puisse comparer les deux listes conjointement.

    J'ai tenté d'exploiter l'attribut __PARENT ajouté à la dernière ligne de l'extension et sensé référencer le parent de la classe en question (donc du this de newFN), sauf qu'il est "undefined" lors de l'appel de newFN (donc du constructeur de la classe), ce qui n'est pas logique : l'extension intervient avant la construction, cet attribut devrait donc être défini lors de cette deuxième phase.

    J'ai probablement manqué un épisode mais quelle est mon erreur?

    Merci par avance de ce dernier coup de pouce, bon après-midi.

  17. #57
    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,

    Malgré tous mes efforts, aucune méthode ne semble fonctionner correctement.
    Le pire c'est que je ne comprends pas tellement pourquoi, Javascript est vraiment un langage pas facile à appréhender.

    De plus, en reprenant le dernier code établit pas willpower plus haut dans sa version la plus avancée, visiblement les membres privés des classes parent ne sont pas copiés dans le prototype de l'enfant.
    Voici un exemple :

    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
    54
    55
    56
    57
    58
    59
    60
    61
    62
     
    var GrandPere = function(){
      // Attributs privés
      var _attr1 = null;
     
      // Méthodes
      this.__construct (){
        alert ("__construct GrandParent");
        this._attr1 = "value";
        alert (this.__attr1); // <- Affiche "undefined". Il se moque de qui, on vient de l'affecter une ligne au dessus!
     
      }
     
      // D'autres méthodes...
      this.access (){
         alert (this._attr1);
      }
    }
     
     
    var Parent = function (){
      // Attributs privés
      var _attr2 = null;
     
      // Méthodes
      this.__construct (){
         alert ("__construct Parent");
         this.__super.__construct();
     
         alert (this._attr1); // Idem que précédemment mais là c'est normal vu que _attr1 est privé
     
         this.access(); // Undefined mais là c'est moins normal.
      }
    }
    Parent = Parent.extends (GrandPere);
     
     
    var Enfant = function (){
      Attributs privés
      var _attr3 = null;
     
      // Méthodes
      this.__construct (){
        alert ("__construct Enfant");
        this.__super.__construct();
     
        this.access(); // undefined!
      }
    }
    Enfant = Enfant.extends(Parent);
     
     
    // Démo
    var fils = new Enfant();
    fils.__construct ();
     
    // Résumé des alert ():
    // "__construct Enfant"
    // "__construct Parent"
    // "__construct GrandParent"
    // "undefined"
    // ...
    C'est bizarre non?

    A noter que j'ai sorti l'appel de __construct du constructeur javascript puisque comme je l'ai dit au dessus, ces méthodes seraient toutes appelée avec les paramètres donnés au constructeur de la classe Enfant, ce qui n'est pas forcément correct puisque les constructeurs parent peuvent une signature complètement différente.

    Régler cet n-ième problème me permettra d'y voir déjà plus clair et de disposer de quelque chose de fonctionnel sans les "bonus" évoqués au dessus.
    Merci par avance.

  18. #58
    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 fanfouer Voir le message
    Bonjour,
    C'est bizarre non?
    En fait non, fausse alerte, rien de bizarre.
    Je viens de comprendre comment on simulait la présence de variables privées : ils ne font pas partie de l'instance mais appartiennent au contexte du constructeur, donc il n'y a pas de raisons d'utiliser this pour les atteindre.

    Par contre, je rencontre encore un soucis (décidément ).
    J'ai l'impression que la surcharge effectuée par extends n'est pas complete.
    Visiblement, tout appel à une méthode surchargée depuis une classe parent (là ou la première méthode est déclarée) appelle en fait la méthode non surchargée.
    Si on appelle ensuite la même méthode mais depuis la classe enfant, la version surchargée est ici appelée.
    Pourquoi le this ne représente pas l'instance en cours ici?

    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
     
    var Parent = function (){
      this.__construct = function (){
        alert ("__construct parent");
        this.test();
      }
     
      // Méthodes
      this.test = function(){
        alert ("parent");
      }
    }
     
    var Enfant = Parent.extends (function (){
      this.__construct = function (){
        alert ("__construct enfant");
        this.test();
     
        this.__super.__construct();
      }
     
      // Méthodes
      this.test = function (){
        alert ("enfant");
        this.__super.test();
      }
    }
     
    var instance = new Enfant();
    instance.__construct();
     
    // Résultat des alert() : 
    // "__construct enfant"
    // "enfant"
    // "parent"
    // "__construct parent"
    // "parent"  <- Pas normal, j'ai instancié un objet de type Enfant, pas un objet de type Parent!
    A noter que j'ai inversé le fonctionnement de extends : Pour coller un peu mieux à d'autres langages que j'utilise, j'ai changé l'unique paramètre par la référence à l'enfant.
    On peut maintenant écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    var Enfant = Parent.extends (function (){
     
    ...
     
    });
    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
     
    Function.prototype.extends = function(FN){
    	var parent = this;
     
    	var newFN = function(){
    		parent.apply(this, arguments);
     
    		// Gestion de super
    		this.__super = this.__super ? {__super:this.__super} : {};
    		for(var i in this){
    			if(typeof this[i] == "function"){
    				this.__super[i] = this[i];
    			}
    		}
     
    		var result = FN.apply(this, arguments);
     
    		return result;
    	};
     
    	var proto = function(){};
    	proto.prototype = parent.prototype;
    	newFN.prototype = new proto();
     
    	for(var i in FN.prototype){
    		newFN.prototype[i] = FN.prototype[i];
    	}
     
    	// copie des statiques parents
    	for(var i in parent){
    		newFN[i] = parent[i];
    	}
     
    	// copie(+ecrase) des statiques nouveau
    	for(var i in FN){
    		newFN[i] = FN[i];
    	}
     
    	newFN.__PARENT = parent;
    	return newFN;
    }
    Cela ne pose pas de problèmes particuliers, j'ai testé les deux méthodes pour voir si ce n'était pas ce qui faisait dérailler la surcharge.

    Puis-je avoir l'avis de l'un d'entre-vous?

    Merci par avance.

  19. #59
    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
    Quel honneur d'utiliser mon code.


    Même si je pense qu'il doit exister mieux et surtout que ce n'est pas une bonne chose de l'utiliser car je maintiens ce que je disais dans mes premiers postes, utiliser un langage orienté classe et prototype de la même manière qu'un langage OO n'est pas approprié et donc pas une bonne chose. (Même si tu as donné tes arguments.)


    Quant à ton erreur, je regarderais ça tantôt ou ce soir.

  20. #60
    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
    Quel honneur d'utiliser mon code.
    C'était parti pour et si il est bon c'est bien normal

    Même si je pense qu'il doit exister mieux et surtout que ce n'est pas une bonne chose de l'utiliser car je maintiens ce que je disais dans mes premiers postes, utiliser un langage orienté classe et prototype de la même manière qu'un langage OO n'est pas approprié et donc pas une bonne chose. (Même si tu as donné tes arguments.)
    Je dirais même mieux : l'optimalité est donnée par rapport à une référence. Je pense que tu entends le "pas une bonne chose" par rapport aux objectifs premiers du langage qui ne sont pas forcément les miens.
    On se base quand même sur des fondements solides, pas des hacks dépendant du navigateur, il y a donc de fortes chances que le code continue à marcher par la suite.

    Quant à ton erreur, je regarderais ça tantôt ou ce soir.
    Merci par avance!

+ Répondre à la discussion
Cette discussion est résolue.
Page 3 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