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 :

Factories et opérateur instanceof en ES5


Sujet :

JavaScript

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Rédacteur/Modérateur

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

    Informations forums :
    Inscription : Novembre 2012
    Messages : 3 375
    Par défaut Factories et opérateur instanceof en ES5
    Hello,

    A mon tour de poser une question pour changer. Je souhaiterai une écrire une factory (fonction constructeur de fonctions) et respecter la chaîne prototypale, c'est-à-dire new Factory() instanceof FactoryAvec les constructeurs classiques retournant un objet, c'est le comportement par défaut. Mais quand il s'agit de retourner une fonction, c'est beaucoup plus délicat.

    Exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    function MultiplierFactory(n1){
        return function(n2){ return n1*n2; };
    }
     
    var multiplyBy3 = new MultiplierFactory(3);
    multiplyBy3(7) 
    > 21
    multiplyBy3 instanceof MultiplierFactory
    > false
    La seule option que j'ai trouvé est de modifier dynamiquement le prototype via Object.setPrototypeOf:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function MultiplierFactory(n1){
        var f = function(n2){ return n1*n2; };
        Object.setPrototypeOf(f, MultiplierFactory.prototype);
        return f;
    }
     
    var multiplyBy3 = new MultiplierFactory(3);
    multiplyBy3(7) 
    > 21
    multiplyBy3 instanceof MultiplierFactory
    > true
    Ce qui fonctionne sur tous les navigateurs supportant Object.setPrototypeOf. Mais que faire dans le cas d'IE9 et inférieur ? Existe-t-il une solution en EcmaScript 5 pour parvenir à ce résultat ?

    Merci d'avance

  2. #2
    Rédacteur

    Avatar de danielhagnoul
    Homme Profil pro
    Étudiant perpétuel
    Inscrit en
    Février 2009
    Messages
    6 389
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 74
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant perpétuel
    Secteur : Enseignement

    Informations forums :
    Inscription : Février 2009
    Messages : 6 389
    Billets dans le blog
    125
    Par défaut
    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
    // "Class" Multiplier
    function Multiplier( n1, n2 ){
        this.result = n1 * n2;
    }
     
    // Construction de la factory avec n1 = 7
    // pattern : http://addyosmani.com/resources/essentialjsdesignpatterns/book/#factorypatternjavascript
     
    function MultiplierFactory(){}
     
    MultiplierFactory.prototype.multiplierClass = Multiplier;
     
    MultiplierFactory.prototype.createMultiplier = function( n2 ){
        return new this.multiplierClass( 7, n2 );
    };
     
    // Utilisation de la factory
     
    var multiplierFactory = new MultiplierFactory(),
        multiplierBy3 = multiplierFactory.createMultiplier( 3 ),
        multiplierBy4 = multiplierFactory.createMultiplier( 4 ),
        multiplierBy5 = multiplierFactory.createMultiplier( 5 );
     
    // true
    console.log( multiplierBy3 instanceof Multiplier );
     
    // 7 * 3 = 21
    console.log( multiplierBy3.result );
     
    // true
    console.log( multiplierBy4 instanceof Multiplier );
     
    // 7 * 4 = 28
    console.log( multiplierBy4.result );
     
    // true
    console.log( multiplierBy5 instanceof Multiplier );
     
    // 7 * 5 = 35
    console.log( multiplierBy5.result );
    EDIT : je réalise que je n'ai pas répondu au problème : "retourner une fonction". Mais que l'on passe par le pattern ou par Object.setPrototypeOf() on en arrive toujours à manipuler un objet.

    EDIT2 :

    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
    Object.setPrototypeOf = Object.setPrototypeOf || function( obj, proto ){
      obj.__proto__ = proto;
      return obj; 
    };
     
    // test obj.__proto__ = proto;
     
    function MultiplierFactory(n1){
        var f = function(n2){ return n1*n2; };
        f.__proto__ = MultiplierFactory.prototype;
        return f;
    }
     
    var multiplyBy3 = new MultiplierFactory(3);
     
    console.log( multiplyBy3(7) );
    console.log( multiplyBy3 instanceof MultiplierFactory );

    Blog

    Sans l'analyse et la conception, la programmation est l'art d'ajouter des bogues à un fichier texte vide.
    (Louis Srygley : Without requirements or design, programming is the art of adding bugs to an empty text file.)

  3. #3
    Rédacteur

    Avatar de danielhagnoul
    Homme Profil pro
    Étudiant perpétuel
    Inscrit en
    Février 2009
    Messages
    6 389
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 74
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant perpétuel
    Secteur : Enseignement

    Informations forums :
    Inscription : Février 2009
    Messages : 6 389
    Billets dans le blog
    125
    Par défaut
    Solution avec Object.create() :

    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
    function MultiplierFactory( n1 ){
        return function( n2 ){
            return n1*n2;
        };
    }
     
    MultiplierFactory.prototype = {};
     
    var multiplyBy3 = Object.create( MultiplierFactory.prototype, {
        "f" : {
            "value" : MultiplierFactory( 7 )
        }
    });
     
    console.log( multiplyBy3.f( 3 ) );
    console.log( multiplyBy3 instanceof MultiplierFactory );
    console.log( Object.getPrototypeOf( multiplyBy3 ) );

    Blog

    Sans l'analyse et la conception, la programmation est l'art d'ajouter des bogues à un fichier texte vide.
    (Louis Srygley : Without requirements or design, programming is the art of adding bugs to an empty text file.)

  4. #4
    Rédacteur/Modérateur

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

    Informations forums :
    Inscription : Novembre 2012
    Messages : 3 375
    Par défaut
    __proto__ n'est pas standard et n'est pas présent non plus sur IE <= 9.

    Les autres solutions proposées ne retournent pas une fonction. J'ai besoin que multiplyBy3 instanceof MultiplierFactory && multiplyBy3 instanceof Function. C'est là le coeur du problème

  5. #5
    Membre Expert

    Homme Profil pro
    Ingénieur Hospitalier
    Inscrit en
    Juillet 2004
    Messages
    993
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur Hospitalier
    Secteur : Santé

    Informations forums :
    Inscription : Juillet 2004
    Messages : 993
    Billets dans le blog
    1
    Par défaut Pas top :(
    Salut sujet intéressant j'ai trouvé une solution mais je sais pas si cela est ce que tu recherche vraiment :

    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
     
    function MultiplierFactory(n1){
        var f = function(n2){ return n1*n2; };
        //f.__proto__ = MultiplierFactory.prototype   //ES6
        //Object.setPrototypeOf(f, MultiplierFactory.prototype); //ES6
       //TEST ES5 -> jusqu'a IE5 en émulation
        f.constructor.prototype = function(f) {
           function f () {}
           f.prototype = proto
           return new f
        }
     
        return f;
    }
     
     
    var multiplyBy3 = new MultiplierFactory(3);
    console.log(multiplyBy3(7))
     
    multiplyBy3 instanceof MultiplierFactory
     
    MultiplierFactory.prototype = new MultiplierFactory(7);
     
    var multiplyBy4 = new MultiplierFactory(7);
    console.log(multiplyBy4(7))
    multiplyBy4 instanceof MultiplierFactory.constructor; // true
    Je sais pas si c'est ce que tu souhaite j'aurais testé au moins gl.

  6. #6
    Rédacteur

    Avatar de danielhagnoul
    Homme Profil pro
    Étudiant perpétuel
    Inscrit en
    Février 2009
    Messages
    6 389
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 74
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant perpétuel
    Secteur : Enseignement

    Informations forums :
    Inscription : Février 2009
    Messages : 6 389
    Billets dans le blog
    125
    Par défaut
    Citation Envoyé par SylvainPV Voir le message
    J'ai besoin que multiplyBy3 instanceof MultiplierFactory && multiplyBy3 instanceof Function. C'est là le coeur du problème
    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 getType( Obj ){
        return Object.prototype.toString.call( Obj ).match( /\s([a-zA-Z]+)/ )[ 1 ].toLowerCase();
    }
     
    function MultiplierFactory(n1){
        var f = function( n2 ){ return n1*n2; };
        Object.setPrototypeOf( f, MultiplierFactory.prototype );
        return f;
    }
     
    MultiplierFactory.prototype = Function.prototype;
     
    var multiplyBy3 = new MultiplierFactory( 7 );
     
    console.log( multiplyBy3( 3 ) ); // 21
    console.log( getType( multiplyBy3 ) ); // function
    console.log( multiplyBy3 instanceof MultiplierFactory ); // true
    console.log( multiplyBy3 instanceof Function ); // true
    Citation Envoyé par SylvainPV Voir le message
    __proto__ n'est pas standard et n'est pas présent non plus sur IE <= 9.
    Oui. Comme d'habitude, le vrai problème c'est les versions obsolètes de IE.

    Citation Envoyé par SylvainPV Voir le message
    Les autres solutions proposées ne retournent pas une fonction.
    Oui. Avec Object.create() il sera difficile de faire autrement.

    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
    function getType( Obj ){
        return Object.prototype.toString.call( Obj ).match( /\s([a-zA-Z]+)/ )[ 1 ].toLowerCase();
    }
     
    function MultiplierFactory( n1 ){
        return function( n2 ){
            return n1*n2;
        };
    }
     
    MultiplierFactory.prototype = Function.prototype;
     
    var multiplyBy3 = Object.create( MultiplierFactory.prototype, {
        "f" : {
            "value" : MultiplierFactory( 7 )
        }
    });
     
    console.log( multiplyBy3.f( 3 ) ); // 21
    console.log( getType( multiplyBy3.f ) ); // function
    console.log( multiplyBy3 instanceof MultiplierFactory ); // true
    console.log( multiplyBy3 instanceof Function ); // true
    Citation Envoyé par SylvainPV Voir le message
    J'ai besoin que multiplyBy3 instanceof MultiplierFactory && multiplyBy3 instanceof Function. C'est là le coeur du problème
    C'est aussi la solution.

    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 getType( Obj ){
        return Object.prototype.toString.call( Obj ).match( /\s([a-zA-Z]+)/ )[ 1 ].toLowerCase();
    }
     
    function MultiplierFactory( n1 ){
        return function( n2 ){
            return n1*n2;
        };
    }
     
    MultiplierFactory.prototype = Function.prototype;
     
    var multiplyBy3 = new MultiplierFactory( 7 );
     
    console.log( multiplyBy3(3) ); // 21
    console.log( getType( multiplyBy3 ) ); // function
    console.log( multiplyBy3 instanceof MultiplierFactory ); // true
    console.log( multiplyBy3 instanceof Function ); // true

    Blog

    Sans l'analyse et la conception, la programmation est l'art d'ajouter des bogues à un fichier texte vide.
    (Louis Srygley : Without requirements or design, programming is the art of adding bugs to an empty text file.)

  7. #7
    Rédacteur/Modérateur

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

    Informations forums :
    Inscription : Novembre 2012
    Messages : 3 375
    Par défaut
    @headmax: non ça ne va pas non plus, avec la redéfinition du prototype multiplyBy4 n'est pas une instance de MultiplierFactory. MultiplierFactory.constructor correspond simplement au constructeur Function.

    @daniel: oui je crois que tu as trouvé avec ton dernier exemple Mais je ne parviens pas à comprendre comment ça marche... comparé à mon exemple initial, il a fallu simplement rajouter MultiplierFactory.prototype = Function.prototype; pour valider le test d'instanceof sur MultiplierFactory (et non celui sur Function ??? j'aurais cru l'inverse).

    J'ai aussi une autre contrainte que je n'ai pas encore mentionné, c'est que j'ai des variables et méthodes dans le prototype de mes factories. S'il correspond à Function.prototype, je vais modifier le prototype de toutes les fonctions et ce n'est pas du tout ce que je souhaite. Or je ne vois pas comment hériter de ce prototype sans casser la solution...

    edit: je pense avoir compris. En assignant le proto de la Factory au proto de Function, on aura toujours model instanceof Factory && model instanceof Function puisque Object.getPrototypeOf(model) === Function.prototype && Function.prototype === Factory.prototypeLa Factory produit des fonctions avec le prototype de base des fonctions, donc toute fonction déclarée (dont celle de l'instruction return dans le code de la Factory) sera assimilée à une instance de cette Factory. Si je déclare n'importe quelle fonction, on aura:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    console.log( (function(){}) instanceof MultiplierFactory );
    > true
    Donc ça marche, mais ça ne résout pas du tout mon problème puisque ça revient à déclarer la fonction normalement. Or mon but était de produire des fonctions spécialisées, des fonctions avec un certain prototype particulier héritant de Function.prototype.

Discussions similaires

  1. [Binaire] Opérateurs de rotation dee bits ?
    Par Tifauv' dans le forum C
    Réponses: 3
    Dernier message: 09/11/2017, 11h29
  2. [Windev 9] équivalent de l'opérateur instanceof
    Par le y@m's dans le forum WinDev
    Réponses: 7
    Dernier message: 28/08/2007, 12h43
  3. Opérateur like
    Par Troopers dans le forum ASP
    Réponses: 3
    Dernier message: 15/09/2003, 19h19
  4. opérateur non applicable à ce type d'opérande
    Par Amon dans le forum Langage
    Réponses: 3
    Dernier message: 11/06/2003, 18h07
  5. [imprecis]Réaliser a^n avec seulement l'opérateur d'addition
    Par Amon dans le forum Algorithmes et structures de données
    Réponses: 18
    Dernier message: 08/11/2002, 22h22

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