web-dev-qa-db-fra.com

Modèle de conception JavaScript: différence entre le modèle de module et le modèle de module révélateur?

Je lis le livre Learning JavaScript Design Patterns récemment. Ce que je ne comprends pas, c'est la différence entre modèle de module et modèle de module révélateur. Je pense qu'ils sont la même chose. Tout le monde peut donner un exemple?

52
Wayou

Il existe au moins trois manières différentes d'implémenter le modèle de module, mais le modèle de module de révélation est le seul descendant de modèle de module qui porte un nom officiel.

Le modèle de module de base

Le modèle de module doit satisfaire aux exigences suivantes:

  • Les membres privés vivent dans la fermeture.
  • Les membres publics sont exposés dans l'objet de retour.

Mais il y a beaucoup d'ambiguïté dans cette définition. En résolvant l'ambiguïté différemment, vous obtenez des variantes du modèle de module.

Le modèle de module révélateur

Le modèle de module révélé est la plus célèbre et la plus populaire des variantes de modèle de module. Il présente un certain nombre d'avantages par rapport aux autres alternatives, telles que

  • Renommez les fonctions publiques sans changer de corps de fonction.
  • Modifiez les membres de public à privé ou inversement en modifiant une seule ligne, sans changer le corps de la fonction.

Le PGR remplit trois conditions supplémentaires en plus de celles de l'original:

  • Tous les membres, qu'ils soient publics ou privés, sont définis dans la clôture.
  • L'objet de retour est un littéral d'objet sans définition de fonction. Toutes les expressions du côté droit sont des variables de fermeture
  • Toutes les références se font via les variables de fermeture, pas l'objet de retour.

L'exemple suivant montre comment il est utilisé

var welcomeModule = (function(){
  var name = "John";
  var hello = function(){ console.log("Hello, " + name + "!");}
  var welcome = function() { console.log( hello() + " Welcome to StackOverflow!");}
  return {
    name: name,
    sayHello: hello,
    sayWelcome: welcome
  }
})();

Si vous souhaitez rendre name et sayHello private, il vous suffit de commenter les lignes appropriées dans l'objet de retour.

var welcomeModule = (function(){
  var name = "John";
  var hello = function(){ console.log("Hello, " + name + "!");}
  var welcome = function() { console.log( hello() + " Welcome to StackOverflow!");}
  return {
    //name: name,
    //sayHello: hello,
    sayWelcome: welcome
  }
})();

Le modèle de module avec littéral d'objet

C'est probablement la variante la plus ancienne du modèle de module. Contrairement à RMP, il n’ya pas de nom officiel sexy pour cette variante. 

Il répond aux conditions suivantes, en plus de l'original:

  • Les membres privés sont définis dans la fermeture.
  • Les membres publics sont définis dans le littéral de l'objet de retour.
  • Les références aux membres du public se font via this, dans la mesure du possible.

Dans l'exemple suivant, vous pouvez voir comment, contrairement à RMP, les définitions de fonction sont en réalité dans le littéral de l'objet de retour et que les références aux membres sont qualifiées par this.

var welcomeModule = (function(){
  return {
    name: "John",
    sayHello: function(){ console.log("Hello, " + this.name + "!");}
    sayWelcome: function() { console.log( this.hello() + " Welcome to StackOverflow!");}
  }
})();

Notez que pour que name et sayHello soient privés, les références pointant vers name et sayHello dans les différentes définitions de corps de fonction doivent également être modifiées.

var welcomeModule = (function(){
  var name: "John";
  var sayHello = function(){ console.log("Hello, " + name + "!");};
  return {
    //name: "John",
    //sayHello: function(){ console.log("Hello, " + this.name + "!");}
    sayWelcome: function() { console.log( hello() + " Welcome to StackOverflow!");}
  }
})();

Le modèle de module avec le stub d'objet de retour

Cette variante n'a pas non plus de nom officiel.

Il répond aux conditions suivantes, en plus de l'original:

  • Un stub d'objet de retour vide est défini au début.
  • Les membres privés sont définis dans la fermeture.
  • Les membres publics sont définis comme des membres du stub
  • Les références aux membres publics se font via l'objet stub

En utilisant notre ancien exemple, vous pouvez voir que des membres du public sont directement ajoutés à l'objet stub.

var welcomeModule = (function(){
  var stub = {};
  stub.name = "John";
  stub.sayHello = function(){ console.log("Hello, " + stub.name + "!");}
  stub.sayWelcome = function() { console.log( stub.hello() + " Welcome to StackOverflow!");}
  return stub;
})();

Si vous souhaitez que name et sayHello soient privés comme auparavant, vous devez modifier les références aux membres maintenant privés.

var welcomeModule = (function(){
  var stub = {};
  var name = "John";
  var sayHello = function(){ console.log("Hello, " + name + "!");}

  stub.sayWelcome = function() { console.log( hello() + " Welcome to StackOverflow!");}
  return stub;
})();

Résumé

Les différences entre le modèle de module de révélation et les autres variantes du modèle de module résident principalement dans la façon dont les membres publics sont référencés. En conséquence, RMP est beaucoup plus facile à utiliser et à modifier, ce qui explique sa popularité. Cependant, ces avantages ont un coût énorme (à mon avis), auquel Addy Osmani fait allusion dans son post sur Modèle de module révélateur

Un inconvénient de ce modèle est que si une fonction privée fait référence à une fonction publique, cette fonction publique ne peut pas être remplacée si un correctif est nécessaire. En effet, la fonction privée continuera à faire référence à l'implémentation privée et le modèle ne s'applique pas aux membres publics, mais uniquement aux fonctions.

Les membres d'objets publics qui font référence à des variables privées sont également soumis aux remarques ci-dessus relatives aux règles de non-correctif.

En conséquence, les modules créés avec le modèle de module de révélation peuvent être plus fragiles que ceux créés avec le modèle de module d'origine. Il convient donc de prendre des précautions lors de l'utilisation.

et dont j'ai parlé dans certains autresposts .

98
I-Lin Kuo

Réponse courte, Dans le modèle de module, nous définissons des fonctions dans le renvoi d'objet.

Dans le modèle Révéler le module, nous définissons les fonctions dans la zone de fermeture et utilisons uniquement les noms de variables dans l'objet renvoyé.

Cela simplifie le code et présente de nombreux autres avantages.

1
Sumer

Essayez juste de faire quelque chose en vous basant sur la réponse du meilleur commentaire. Peut-être est-il plus sûr d'appeler une fonction privée en lui passantthis, de sorte que cette fonction privée pourrait référencer une fonction publique avecthisvariable.

J'ai créé un modèle de module révélateur avec le code suivant.

var HTMLChanger = (function () {
    var privateFunc = function () {
        this.sayHello();
    }

    var hello = function () {
        console.log('say Hello');
    }
    var callPrivate = function () {
        privateFunc.call(this);
    }


    return {
        sayHello: hello,
        callPrivate: callPrivate
    };
})();

HTMLChanger.callPrivate();
//say Hello

HTMLChanger.sayHello = function() { console.log('say Hi!') };

HTMLChanger.callPrivate();
//say Hi!

Comme vous pouvez le constater, nous pouvons remplacer un membre public.

0
Semooze