Dans le dernier épisode du podcast Laravel, J’aime les choses que vous dites, nous parlions de VueJS, et Taylor a mentionné qu’il est parfois ennuyeux d’avoir de longs objets que vous faites passer dans les frameworks JavaScript. Vous les connaissez : vous définissez une série de paramètres et de méthodes et vous devez tous les entasser dans une liste séparée par des virgules afin qu’ils soient définis en tant que propriétés sur un objet :
Vue.doSomethingOrOther({
onething: function () {
},
otherThing: function () {
},
etcetera: 'etcetera'
});
Sur le podcast, j’ai mentionné mon amour éternel pour le Modèle de module révélateur et promis un exemple, alors voilà.
Pourquoi avons-nous besoin du modèle de module révélateur ?
J’ai découvert le modèle de module révélateur pour la première fois grâce au livre d’Addy Osmani, Learning JavaScript Design Patterns.
Prenons un exemple rapide pour montrer pourquoi Revealing Module est génial. Supposons que nous voulons un Analytics
objet. Nous voulons pouvoir l’utiliser dans notre JavaScript pour faire des appels à Google Analytics, mais nous voulons une syntaxe plus simple.
var Analytics = {};
Donnons-lui deux méthodes, pageView
et action
.
var Analytics = {
pageView: function () {
GoogleAnalytics.prepSomethingOrOther();
GoogleAnalytics.pushOrSomething('pageView');
},
action: function (key) {
GoogleAnalytics.prepSomethingOrOther();
GoogleAnalytics.pushOrSomething('action', key);
}
};
Eh bien, jetez un œil à cela, c’est un peu de code répété ! Si seulement nous pouvions avoir des méthodes privées, nous pourrions extraire une sorte de méthode `pushOrSomething’ :
var Analytics = {
pushOrSomething: function () {
GoogleAnalytics.prepSomethingOrOther();
// Use function.apply to pass the called parameters along
GoogleAnalytics.pushOrSomething.apply(this, arguments);
},
pageView: function () {
this.pushOrSomething('pageView');
},
action: function (key) {
this.pushOrSomething('action', key);
}
};
Cela semble bien, mais notre gros problème ici est que nous avons maintenant exposé Analytics.pushOrSomething()
au public. De plus, nous ne l’avons pas encore tout à fait atteint, mais lorsque nous commencerons à construire cet objet, nous rencontrerons le point douloureux de Taylor de la liste séparée par des virgules en constante augmentation.
La fonction anonyme auto-exécutable
Le modèle de module révélateur repose sur un concept appelé la fonction anonyme auto-exécutable. Examinons d’abord une fonction anonyme :
var AnalyticsGenerator = function() {
return {};
};
var Analytics = AnalyticsGenerator();
Génial, nous avons donc une fonction sans nom qui renvoie quelque chose SI nous l’exécutons. Mais c’est une syntaxe délicate, surtout si nous ne prévoyons de l’exécuter qu’une seule fois. Si seulement nous pouvions appeler la fonction dès que nous la définissons…
var Analytics = (function() {
return {};
})();
Par George, nous l’avons fait ! Nous venons d’envelopper la fonction entre parenthèses, puis d’ajouter un deuxième ensemble de parenthèses par la suite pour indiquer qu’elle doit être exécutée. Maintenant Analytics
est défini comme le résultat de l’exécution de cette fonction, qui dans ce cas n’est qu’un objet vide.
Le modèle de module révélateur
Enfin. Le motif. Découvrez notre exemple précédent, mais maintenant Revealing-Moduled :
var Analytics = (function () {
var _pushOrSomething = function () {
GoogleAnalytics.prepSomethingOrOther();
// Use function.apply to pass the called parameters along
GoogleAnalytics.pushOrSomething.apply(this, arguments);
};
var pageView = function () {
_pushOrSomething('pageView');
};
var action = function (key) {
_pushOrSomething('action', key);
};
return {
pageView: pageView,
action: action
};
})();
Notez que nous avons mis à jour les appels dans pageView
et action
pour référencer le nom de la fonction sans ceet nous avons préfacé la fonction “privé” pushOrSomething
avec un trait de soulignement, juste comme un rappel pour le garder privé.
À la fin, nous avons défini ce que nous voulons retourner, et tout ce qui n’est pas dans cet objet de retour est “privé” et ne peut pas être appelé par le public. Cela fonctionne également pour les propriétés, et vous pouvez même effectuer toutes sortes de travaux procéduraux, si vous le souhaitez :
var Analytics = (function () {
var variableOrWhatever = 42;
variableOrWhatever *= 1.0;
var _pushOrSomething = function () {
GoogleAnalytics.initialize(variableOrWhatever);
GoogleAnalytics.somethingOrOther();
// Use function.apply to pass the called parameters along
GoogleAnalytics.pushOrSomething.apply(this, arguments);
};
var pageView = function () {
_pushOrSomething('pageView');
};
var action = function (key) {
_pushOrSomething('action', key);
};
return {
variableOrWhatever: variableOrWhatever,
pageView: pageView,
action: action
};
})();
Si vous voulez voir cela fonctionner et voir ce qui se passe lorsque vous essayez d’appeler une méthode “privée”, consultez ce JSBin. Ou, essayez simplement le code ci-dessus et voyez ce qui se passe lorsque vous exécutez Analytics._pushOrSomething
(indice : votre navigateur ne l’appréciera pas).
Le ciel est la limite, les enfants. Maintenant partout vous devez générer un objet JavaScript, vous avez beaucoup plus de liberté pour créer rapidement des méthodes privées et exécuter un code de préparation procédural désagréable au milieu de sa création.
Addenda ES6
Une grande partie de la raison pour laquelle nous avons besoin de ce genre de choses est que JavaScript est basé sur des prototypes, pas sur des classes et des objets. Cela a lentement changé au fil du temps, et ES6 a fait une énorme différence à cet égard. Donc, si vous écrivez ES6, vous trouverez moins utiliser pour ce modèle, mais je suggérerais quand même de le garder dans votre ceinture à outils.