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 :

Date : copier constructeur + fonctions ?


Sujet :

JavaScript

  1. #1
    Membre expérimenté Avatar de Lorenzo77
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    1 472
    Détails du profil
    Informations personnelles :
    Âge : 52
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mai 2006
    Messages : 1 472
    Points : 1 537
    Points
    1 537
    Par défaut Date : copier constructeur + fonctions ?
    salut,

    je cherche a faire une copie complète (constructeur + fonctions) de la classe Date.
    le but : ajouter des fonctions perso mais sans alourdir la classe Date originale.

    j'ai essayé différentes méthodes mais je perds le constructeur ou alors mes fonctions sont aussi ajoutés sur la classe Date originale.

    comment faire cette 'copie' ?
    merci

  2. #2
    Invité
    Invité(e)
    Par défaut
    Salut,

    Tu peux passer par un héritage orienté prototype. Cela peut se faire de plusieurs façons. L'une d'entre elle, utilisée notamment pour le modèle objet de coffeescript :

    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
    function _extends(Child, Parent) {
      function F() {
        this.constructor = Child;
      }
      F.prototype = Parent.prototype;
      Child.prototype = new F();
      Child.super= Parent();
    }
     
    function MyDate() {
      MyDate.super.constructor.apply(this, arguments); // Appel au constructeur parent
    }
     
    _extends(MyDate, Date);
     
    MyDate.prototype.myMethod = function() { /* ... */ };
     
    var date = new MyDate();

    De cette manière, les prototypes sont chainés.
    Tu as ChildInstance__proto__ChildPrototype__proto__ParentPrototype

    Pour les explications :
    • Passer par une fonction F permet de ne pas appeler les instructions du constructeur parent au niveau du prototype enfant. On s'en charge plus tard dans le constructeur de Child directement via l'instruction MyDate.super.constructor.apply(this, arguments);. Ainsi en faisant
      Code JavaScript : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
        function F() {}
        F.prototype = Parent.prototype;
        Child.prototype = new F();
      tu obtiens une fonction F qui ne possède que le prototype de Parent, et dont l'instance va servir de prototype à Child, ce qui te permet de chainer les prototypes.
    • L'instruction this.constructor = Child; permet d'overrider dans le prototype de Child l'attribut constructor de Parent.prototype, qui pointe sur Parent. Ainsi, Child.prototype.constructor sera bien Child et non Parent.


    EDIT : extends -> _extends
    Citation Envoyé par Kaamo Voir le message
    Attention, extends est un mot réservé du langage.
    Dernière modification par Invité ; 29/05/2013 à 14h14.

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

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 1 165
    Points : 2 778
    Points
    2 778
    Par défaut
    Attention, extends est un mot réservé du langage.

    L'idée est bonne et largement employée (CoffeeScript comme mentionné) mais cela ne s'applique pas "aux classes innées (built-in)" du langage. C'est bien pour étendre les "classes customs" qui se basent sur le constructeur de function mais pas pour les éléments natifs (Array, Date, etc). On ne peut pas, ou presque, les étendre.

    Avec ton code, on est censé appeler toutes les méthodes de la classe mère (ici Date), non ? Alors pourquoi :
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Date.UTC(2012,02,30); // ok
    MyDate.UTC(2012,02,30); // has no method 'UTC'
    ou encore :
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    var d = new MyDate();
    console.log(d.getHours()); // this is not a Date object.
    Car, en dur dans le moteur Javascript, chaque méthode de Date va vérifier que l'objet en question est bien une instance de Date. Voici un extrait du code V8 (pour prendre un moteur en exemple) :
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    function DateGetHours() {
      var t = DATE_VALUE(this);
      if (NUMBER_IS_NAN(t)) return t;
      return HOUR_FROM_TIME(LocalTimeNoCheck(t));
    }
    où DATE_VALUE est une macro : DATE_VALUE(arg) = (%_ClassOf(arg) === 'Date' ? %_ValueOf(arg) : ThrowDateTypeError());, qui check donc si l'objet passé est bien une instance de Date.

    Vérification : (ça affiche la propriété interne [[Class]] qui permet de catégoriser les objets JS en fonction de leur instanciation)
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Object.prototype.toString.call(new Date()); // Date
    Object.prototype.toString.call(new MyDate()); // Object

    Donc, si une date n'est pas instanciée en utilisant new Date(), l'objet ne sera pas une Date et ne pourra pas être manipulé comme tel. Contrairement aux autres "wrappers" JS, Date n'a pas de syntaxe littéral (new Object => {}, new Array => [], new Number => 1, new String() => "", etc)

  4. #4
    Membre expérimenté Avatar de Lorenzo77
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    1 472
    Détails du profil
    Informations personnelles :
    Âge : 52
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mai 2006
    Messages : 1 472
    Points : 1 537
    Points
    1 537
    Par défaut

    ben merde alors, j'ai testé cette méthode mais sans résultat :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
            function copier(Enfant, Parent) {
              var F = function () {};
              F.prototype = Parent.prototype;
              Enfant.prototype = new F();
            }
    sauf que derriere je n'avais pas le bon constructeur ..
    probleme, j'arrive pas a utiliser les méthodes de Date ..
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    console.log(date.__proto__.__proto__.getDate());
    renvoit NaN

    j'arrive pas non plus a faire fonctionner le constructeur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    var date = new MyDate(2012, 1, 1, 1, 0, 0, 0);
    console.log(date);


    ------
    Kaamo : donc d'aprés toi il est impossible de faire une copie de Date ?
    donc si je veux des fonctions perso sur Date je dois alourdir Date ..

  5. #5
    Invité
    Invité(e)
    Par défaut
    Erf, désolé, j'aurais du tester la technique. C'est vrai que je ne l'avais utilisée que sur des constructeurs custom, et j'ai pas pensé à tester ça sur Date.

    @Kaamo : merci pour l'explication technique détaillée.
    Franchement, ça me déçoit. Je trouve que ça enlève de la flexibilité

    @Lorenzo77 : du coup effectivement tu ne peux pas faire de copie. Je ne te conseilles cependant pas d'injecter des méthodes dans le prototype de Date.

    Le mieux je pense c'est de faire un wrapper genre :
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    function MyDate(date) {
      this.nestedDate = date;
    }
     
    MyDate.prototype.myMethod = function() {
      /* ... */
    };

    Ou alors tu peux faire une compilation de fonction utilitaires genre :
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    function DateUtils() {}
     
    DateUtils.myMethod = function(date, args) {
      /* ... */
    };

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

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 1 165
    Points : 2 778
    Points
    2 778
    Par défaut
    @Enerian : oui, mais c'est en cours de "résolution" pour la prochaine version d'ECMAScript normalement.

    Comme le fait remarquer Enerian, à part passer par un utilitaire qui prend en paramètre un objet Date ... je ne vois pas d'autres alternatives.

    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var DateUtils = {
      maMethode: function( d ) {
        if (!(d instanceof Date))
          return 'Erreur, date attendue';
     
        return 'Mon heure perso : ' + d.getHours();
      }
    };
     
    console.log(DateUtils.maMethode(new Date())); // Mon heure perso : XX

  7. #7
    Membre expérimenté Avatar de Lorenzo77
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    1 472
    Détails du profil
    Informations personnelles :
    Âge : 52
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mai 2006
    Messages : 1 472
    Points : 1 537
    Points
    1 537
    Par défaut
    c'est bizarre que la classe Date soit si spécial ... j'ai eu le meme probleme en AS3.
    je vais utiliser la 2eme méthode

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

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 1 165
    Points : 2 778
    Points
    2 778
    Par défaut
    Ce n'est pas que Date, mais tous les autres "natifs" en Javascript. (tel que Array par exemple).

    Il faut faire la différence entre :
    - Sous typer un natif A : Créer un sous constructeur B du constructeur A. Les instances de B (créées avec le sous constructeur de B) seraient alors des instances de A.
    - Étendre un natif A : ça serait ajouter des méthodes à son prototype (A.prototype)

    Mais on choisit souvent la deuxième option car la première est quasiment impossible (comme on vient de le voir pour Date) à cause des instances qui ont :
    - des propriétés internes gérées par le moteur Javascript notées entre double crochet : [[Class]], ou encore [[PrimitiveValue]], etc ... qui ne sont pas accessibles directement en Javascript
    - un constructeur qui ne peut pas être appelé comme on appelle une fonction (ou avec super).

    Par exemple, quand une instance de Array est créée (exemple : var tableau = [1, 2, 3]), tableau est accompagné d'une méthode interne (manipulée uniquement par le moteur JS) : [[DefineOwnProperty]]. Cette méthode "écoute" en continue ce qui se passe sur notre tableau. Par exemple, quand on lui ajoute un élément (tableau.push(4);), cette méthode interne se charge d'incrémenter length. C'est transparent pour nous développeur.
    C'est une des raisons pourquoi il est difficile d'étendre ces types natifs de Javascript, à cause de ces fonctions et propriétés invisibles qui ne sont pas "recopiés" lors de l'appel du constructeur.

  9. #9
    Membre expérimenté Avatar de Lorenzo77
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    1 472
    Détails du profil
    Informations personnelles :
    Âge : 52
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mai 2006
    Messages : 1 472
    Points : 1 537
    Points
    1 537
    Par défaut
    merci
    c'est la ou on remarque que le JS est un langage qui est difficile a faire évoluer a cause d'un héritage trop ancien ..

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

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 1 165
    Points : 2 778
    Points
    2 778
    Par défaut
    Je ne pense pas qu'il s'agisse d'un héritage trop ancien. C'est simplement un autre mode d'héritage. Pas du tout tel qu'on le connait "classiquement" (Java pour ne citer que lui).
    Il faut complètement se défaire de l'héritage classique quand on code en Javascript.

    Son système d'héritage est dit par "délégation" et je t'invite à aller creuser de ce coté si tu veux mettre en place un héritage robuste, propre et adapté à Javascript

    Je citerais une analogie que j'ai lu quelque part un jour : "Faire de l'héritage "classique" avec Javascript, c'est comme commander un Happy Meal pour le jeu seulement".

    un exemple simple d'héritage par délégation :
    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
     /* Pour les navigateurs n'implémentant pas ES5 */
    if (!Object.create) {
      Object.create = function(o) {
        function F() {}
        F.prototype = o;
        return new F();
      };
    }
     
    var Personne = {
      init: function(qui) {
        this.moi = qui;
        console.log(this.presenter());
      },
      presenter: function() {
        return "Je suis " + this.moi;
      }
    };
     
    var DvpMembre = Object.create(Personne);
    DvpMembre.presenterPlus = function() {
      console.log(" et je suis sur DVP !");
    };
     
    var personneNormale = Object.create(Personne);
    personneNormale.init("Bob");
     
    var personneDVP = Object.create(DvpMembre);
    personneDVP.init("Kaamo");
    personneDVP.presenterPlus();
     
    console.log(Personne.isPrototypeOf(personneNormale)); // true
    console.log(Personne.isPrototypeOf(personneDVP)); // true
    console.log(DvpMembre.isPrototypeOf(personneDVP)); // true
    console.log(DvpMembre.isPrototypeOf(personneNormale)); // false
    ps : j'ai laissé les majuscules au début des objets que l'on pourraient qualifier de "classe" mais ce ne sont que des objets simples.

  11. #11
    Membre expérimenté Avatar de Lorenzo77
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    1 472
    Détails du profil
    Informations personnelles :
    Âge : 52
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mai 2006
    Messages : 1 472
    Points : 1 537
    Points
    1 537
    Par défaut
    génial l'exemple !

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

Discussions similaires

  1. [Dates] Limite des fonctions natives DATE
    Par gloubi dans le forum Langage
    Réponses: 11
    Dernier message: 15/08/2007, 19h39
  2. [Dates] "concaténation" de fonction substr et autres
    Par javaboy dans le forum Langage
    Réponses: 12
    Dernier message: 12/04/2007, 10h51
  3. Réponses: 5
    Dernier message: 21/03/2006, 21h39
  4. [Dates] message en fonction d'une date
    Par chouchouboy dans le forum Langage
    Réponses: 14
    Dernier message: 24/02/2006, 17h31
  5. [Dates] pb avec fonction filemtime
    Par xave dans le forum Langage
    Réponses: 40
    Dernier message: 15/11/2005, 09h13

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