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 :

Créer un nouvel Objet/Class au sein d'une IIFE avec une variable comme nom (Factory Pattern)


Sujet :

JavaScript

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2013
    Messages
    54
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2013
    Messages : 54
    Points : 32
    Points
    32
    Par défaut Créer un nouvel Objet/Class au sein d'une IIFE avec une variable comme nom (Factory Pattern)
    Bonjour/bonsoir,

    Je me demandais si il était possible de créer un objet dont le nom serait une variable, mais le tout au sein d'une fonction voir une IIFE.

    Ceci fontionne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    function Person() {};
    var name = 'Person';
    var inst = new this[name];
    console.log('inst :', inst);
    et je n'arrive pas a faire ceci, puisque le this se réfère a l'objet Window
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    let iife = (function () {
      function Person() {};
      var name = 'Person';
      // console.log('this :', this); // => Window*{postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window,*…}
      var inst = new this[name];
      console.log('inst IFFE :', inst); // => Uncaught TypeError: this[name] is not a constructor
    })();
    J'ai beau essayé toute sorte de truc, mais impossible pour moi de le faire fonctionner..



    J'aurai aussi aimer savoir si c’était une bonne idée de "coder" comme cela?!

    Pour la petite histoire, j’apprends a utiliser les Factory Pattern (https://addyosmani.com/resources/ess...ternjavascript).
    Et je me disais, pourquoi coder en dur le nom des objet que je veux créer?
    Si c'est pour utiliser une Factory Pattern, autant créer une fonction qui permet de créer l'objet que l'on veut en lui passant le nom en paramètre et qu'elle me retourne l'Objet/Class.

    Dans l'exercice que j'ai reçu a faire en formation, on nous demande de créer des Objets/Class sur la base d'un fichier json contentant des infos sur des Guest et des Vip. Leurs propriétés sont les mêmes (nom, prenom, ...).
    Mon idée était de faire une 'superClass' Person contenant le squelette et de créer a la volée un Objet de type Guest ou Vip via cette fameuse Factory Pattern, elle même dans une IIFE pour n'exposer que la fonction 'createObject(className)'

    En définitive, j'ai du m'en résoudre a ce bout de code au sein de ma fonction IIFE ObjectFactory
    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
      function objectFactory(someUser) {
     
     
        switch (someUser.userClass) {
          case 'Guest':
            this.userClass = Guest;
            break;
          case 'Vip':
            this.userClass = Vip;
          default:
            break;
        }
     
        return this.userClass(someUser);
      };
    Ce qui va un peu a l'encontre de ce que je voulais faire

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
      function objectFactory(someUser) {
     
        this.userClass = someUser.userClass;
        return this.userClass(someUser);
     
      };
    Bref, je ne pensais pas être aussi long

    Que me conseillez vous ??

  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
    Points : 22 933
    Points
    22 933
    Billets dans le blog
    125
    Par défaut


    Exemple :

    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
    let Person = (function () {
        let pers = function (n, p) {
            this.nom = n;
            this.prenom = p;
        };
     
        pers.prototype = {
            toString() {
                return this.nom + ' ' + this.prenom;
            }
        }
     
        return pers;
    })();
     
    let moi = new Person('Hagnoul', 'Daniel');
     
    console.log(moi);
     
    console.log(moi.toString());

    Une IIFE n'est plus très utile, let et const réduisent la portée au bloc de code, les modules permettent un contrôle très strict des importations et des exportations de code. Les class sont bien pratiques.


  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2013
    Messages
    54
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2013
    Messages : 54
    Points : 32
    Points
    32
    Par défaut
    Merci de ta réponse

    Même si j'ai bien aimer décortiquer ton code, et d'en apprendre un peu plus au passage, je ne vois pas très bien en quoi il répond a mes interrogations sur comment utiliser un variable contenant une string comme nom de fonction (ici l'appel au constructeur) quand on se trouve dans une fonction de type IIFE?!
    De plus, avec ton code, je ne peux créer qu'une instance de Person
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    console.log('moi instanceof Person :', moi instanceof Person);
    La ou moi j'aimerai avoir le choix de l'Objet/Class, Vip ou Guest ou n'importe quel autre Object/Class que je voudrais rajouter.

  4. #4
    Expert éminent
    Avatar de Watilin
    Homme Profil pro
    En recherche d'emploi
    Inscrit en
    Juin 2010
    Messages
    3 094
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 094
    Points : 6 755
    Points
    6 755
    Par défaut
    Bonjour,

    tu as deux cas de figure selon que tu es en mode strict ou pas.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    (function () {
      console.log(this);              // Window {…}
      console.log(this === window);   // true
    })();
     
    (function () {
      "use strict";
      console.log(this);              // undefined
      console.log(this === window);   // false
    })();
    Comme tu peux le voir, en mode strict, this est undefined. Ce comportement permet d’éviter des fuites de données dans l’espace global quand on veut instancier un objet mais qu’on oublie le mot-clé new.

    Mais JavaScript est souple et te permet de modifier le contexte this d’une fonction à l’aide des méthodes call, apply et bind :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    (function () {
      "use strict";
      console.log(this);              // Window {…}
      console.log(this === window);   // true
    }).call(window);
     
    let boundFunction = (function () {
      "use strict";
      console.log(this);              // Window {…}
      console.log(this === window);   // true
    }).bind(window);
     
    boundFunction();
    Citation Envoyé par Dunkhan Voir le message
    J'aurai aussi aimer savoir si c’était une bonne idée de "coder" comme cela?!
    Il est souvent recommandé de ne pas utiliser trop de variables globales, pour plusieurs raisons :
    • parce que ça crée des risques de collisions de noms ;
    • parce que ce n’est pas optimal — une variable globale coûte plus de temps qu’une variable locale, car le moteur JS doit « remonter » plus loin dans la pile des portées ;
    • parce que tes variables sont exposées à tous les vents et peuvent être modifiées, volontairement ou accidentellement, par du code tiers.


    Attention aussi à un aspect de let qui, je crois, n’est pas très connu : les variables globales ne sont plus des propriétés de window.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    var x = 1;
    let y = 2;
     
    console.log(window.x); // 1
    console.log(window.y); // undefined



    Pour répondre directement à ta question :
    et je n'arrive pas a faire ceci, puisque le this se réfère a l'objet Window

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    let iife = (function () {
      function Person() {};
      var name = 'Person';
      // console.log('this :', this); // => Window*{postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window,*…}
      var inst = new this[name];
      console.log('inst IFFE :', inst); // => Uncaught TypeError: this[name] is not a constructor
    })();
    J'ai beau essayé toute sorte de truc, mais impossible pour moi de le faire fonctionner..
    Tu pourrais déclarer un objet contenant tes différents constructeurs et le placer dans la même porté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
    let iife = (function () {
      var constructors = {
        'Person': function Person() {
          ...
        },
        'Capybara': function Capybara() {
          ...
        },
      };
     
      var name = 'Person';
      var inst = new constructors[name];
      console.log('inst IIFE :', inst);
    })();
    (Note au passage : ta fonction ne renvoie rien, et ta variable iife reçoit undefined. Je pense que cette variable n’est pas utile.)

    Ainsi, même pas besoin d’utiliser this, et tu améliores la lisibilité de ton code en utilisant un nom plus explicite.

    Et s’il s’agit d’utiliser des fonctions qui ont été déclarées dans l’espace global :
    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
    function Person() {
      ...
    }
     
    function Capybara() {
      ...
    }
     
    // let iife =
    (function () {
      var constructors = {
        'Person'   : Person,
        'Capybara' : Capybara,
      };
     
      var name = 'Person';
      var inst = new constructors[name];
      console.log('inst IIFE :', inst);
    })();
    En fait, l’objet constructors joue simplement le rôle d’un dictionnaire, et tu peux le remplacer par une Map :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    (function () {
      var constructors = new Map();
      constructors.set('Person', Person);
      constructors.set('Capybara', Capybara);
     
      var name = 'Person';
      var inst = new (constructors.get(name)); // les parenthèses sont nécessaires
      console.log('inst IIFE :', inst);
    })();
    Bref, à toi de choisir la solution que tu préfères

  5. #5
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2013
    Messages
    54
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2013
    Messages : 54
    Points : 32
    Points
    32
    Par défaut
    Désoler pour la réponse tardive, Formation, examen touca..

    Merci beaucoup, c'est très clair comme explication, je vais tester tout ca


    Citation Envoyé par Watilin Voir le message
    (Note au passage : ta fonction ne renvoie rien, et ta variable iife reçoit undefined. Je pense que cette variable n’est pas utile.)

    Pour ce qui est de la variable let iife = (function () {})();, en fait, dans mon code, elle s'appelle ObjectFactory et je m'en sers pour appeler la fonction interne objectFactory que je rend public grâce a un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
       return {
        // Alias for public members
        //****************************
        createObject: objectFactory,
      };
    Et je l'appel dans une autre fonction IIFE avec ObjectFactory.createObject(obj), obj etant le retour d'un json qui contient toutes les infos(propriétés) dont j'ai besoin pour construire mes Class/Objects.

    Je ne dis pas que c'est la façon de faire la plus optimisée ou qui convient le mieux dans le cas de l'exercice que je réalise, mais j'aime incorporer des notions de ce que j’étudie dans mes codes pour "me faire la main", ici les design pattern.



    J'aurai une autre question concernant cette exercice.

    J'utilise donc une fonction IIFE coffeMachine qui lit le retour d'un JSON, contenant des infos sur des groupes de personnes (vip ou guest).
    Je le vérifie et si les propriétés de l’objet sont celle que j’attends, je regarde a quel groupe doit appartenir chaque personne, j'y rajoute une propriété définissant la Class (Vip/Guest) qui devra être utilisé pour créer l'Objet de chaque personne et j'appel ObjectFactory.createObject(obj).

    Dans cette autre fonction IIFE ObjectFactory je retrouve la propriété Class et je m'en sers pour créer la dite Class. Jusque la tout va bien.. Ce qui me chiffone, c'est que dans cette fonction ObjectFactory, je dois écrire en dur le nom des Class que je veux créer pour appeler le bon constructor, et je ne sais pas pourquoi, mais ca m'em.. j'aimerais que cette fonction me crée une Class sans savoir ce qu'elle crée en fait, puisque de toute façon ce sont toutes les "mêmes" Class d'Object qui contiennent toutes les mêmes propriétés et que je construit grâce a une "super Class" Person via un Person.call(this, obj)Le but est que si par exemple je lui envoie une nouvelle Class, par exemple "Membre", je ne doive rien changer au code de cette fonction..
    Je me demandais si un autre fichier externe contenant, je ne sais pas, une fonction ou un objet, avec les noms des fonctions à appeler et dans lequel je pourrais y ajouter les noms des nouvelles class, voir même le mettre a jour de façon dynamique.. ??

    Et je me demandais si cela était possible, voir conseiller, ou si c’était une très mauvaise pratique du point de vue "Code" d'une application.

    Depuis que je repris des études d'infos (cours du soir, je suis en fin de deuxième année), je cherche encore un peu les limites que je peux franchir ou non dans la réalisation d'un code "propre". C'est un peu un des points noir de mes études, on n'y étudie pas du tout la réalisation d'une application du début a la fin.. et on est un peu dans le flou quand a comment penser l'architecture, propre, modulable et robuste, d'une application..

    Je ne demande évidement pas un cours sur la question, je lis et regarde tout ce que je peux sur le sujet, mais je serais très intéressé par votre (vos) avis sur la question!

  6. #6
    Expert éminent
    Avatar de Watilin
    Homme Profil pro
    En recherche d'emploi
    Inscrit en
    Juin 2010
    Messages
    3 094
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 094
    Points : 6 755
    Points
    6 755
    Par défaut
    Citation Envoyé par Dunkhan Voir le message
    En définitive, j'ai du m'en résoudre a ce bout de code au sein de ma fonction IIFE ObjectFactory
    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
      function objectFactory(someUser) {
     
     
        switch (someUser.userClass) {
          case 'Guest':
            this.userClass = Guest;
            break;
          case 'Vip':
            this.userClass = Vip;
          default:
            break;
        }
     
        return this.userClass(someUser);
      };
    Citation Envoyé par Dunkhan Voir le message
    […] si les propriétés de l’objet sont celle que j’attends, je regarde a quel groupe doit appartenir chaque personne, j'y rajoute une propriété définissant la Class (Vip/Guest) qui devra être utilisé pour créer l'Objet de chaque personne et j'appel ObjectFactory.createObject(obj).

    Dans cette autre fonction IIFE ObjectFactory je retrouve la propriété Class et je m'en sers pour créer la dite Class.
    Si j’ai bien suivi, dans ta fonction coffeeMachine, tu assignes des chaînes correspondant aux fonctions « fabriques ». Et ensuite, dans ta fonction ObjectFactory tu utilises ces chaînes pour retrouver la fonction correspondante. Pourquoi ne pas assigner directement les fonctions à tes objets, dans ta fonction coffeeMachine ?

    Si tu ajoutes un type de personne plus tard, c’est le format JSON que tu fais évoluer. Ça me paraît logique que ce soit la fonction chargée d’analyser ce JSON qui soit alors modifiée.


    Citation Envoyé par Dunkhan Voir le message
    Et je me demandais si cela était possible, voir conseiller, ou si c’était une très mauvaise pratique du point de vue "Code" d'une application.
    C’es une façon de faire comme une autre. S’il y avait un parton universellement reconnu comme meilleur que les autres, tu en aurais entendu parler, je pense.
    Il y a sur ce forum une longue discussion qui traite des différentes façons d’instancier des objets : L’Opérateur new, bonne ou mauvaise pratique ? Si tu ne l’as pas encore consultée, je t’invite à y jeter un œil, tu y trouveras sûrement de quoi faire avancer ta réflexion.

  7. #7
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2013
    Messages
    54
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2013
    Messages : 54
    Points : 32
    Points
    32
    Par défaut
    Désoler pour le delai de réponse, j'etais en période d'examen, et j'ai du mettre javascript un peu sur le coté..


    Je vais etudier les réponses que j'ai eu, voir si je comprend.. et revenir vers vous si jamais..

    Encore merci pour vos réponses

Discussions similaires

  1. Réponses: 14
    Dernier message: 03/02/2016, 14h19
  2. Créer un nouvel objet à partir du nom de la classe de l'objet
    Par gueuldange dans le forum Débuter avec Java
    Réponses: 2
    Dernier message: 13/04/2015, 21h37
  3. Réponses: 4
    Dernier message: 13/06/2014, 11h37
  4. [E-03] Créer ses propres objets / classes
    Par NikoBe dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 25/03/2009, 13h50
  5. Créer un nouvel objet dont on ne connait que le type
    Par NicolasJolet dans le forum C#
    Réponses: 1
    Dernier message: 08/02/2007, 09h02

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