Modèle de module JavaScript avec exemple [fermé]

136

Je ne trouve pas d'exemples accessibles montrant comment deux (ou plus) modules différents sont connectés pour fonctionner ensemble.

Alors, je voudrais demander si quelqu'un a le temps d'écrire un exemple expliquant comment les modules fonctionnent ensemble.

Srle
la source
Tout cela a changé au cours des quatre dernières années, mais grâce à la sur-modération zélée, cette information obsolète restera à jamais . Voici la page de MDN sur les modules ES6.
bbsimonbb

Réponses:

256

Pour aborder le modèle de conception modulaire, vous devez d'abord comprendre ces concepts:

Expression de fonction immédiatement invoquée (IIFE):

(function() {
      // Your code goes here 
}());

Vous pouvez utiliser les fonctions de deux manières. 1. Déclaration de fonction 2. Expression de fonction.

Voici l'utilisation de l'expression de fonction.

Qu'est-ce que l'espace de noms? Maintenant, si nous ajoutons l'espace de noms au morceau de code ci-dessus, alors

var anoyn = (function() {
}());

Qu'est-ce que la fermeture dans JS?

Cela signifie que si nous déclarons une fonction avec une portée variable / à l'intérieur d'une autre fonction (dans JS, nous pouvons déclarer une fonction dans une autre fonction!), Alors cela comptera toujours cette portée de fonction. Cela signifie que toute variable de la fonction externe sera toujours lue. Il ne lira pas la variable globale (le cas échéant) avec le même nom. C'est également l'un des objectifs de l'utilisation d'un modèle de conception modulaire évitant les conflits de noms.

var scope = "I am global";
function whatismyscope() {
    var scope = "I am just a local";
    function func() {return scope;}
    return func;
}
whatismyscope()()

Nous allons maintenant appliquer ces trois concepts que j'ai mentionnés ci-dessus pour définir notre premier modèle de conception modulaire:

var modularpattern = (function() {
    // your module code goes here
    var sum = 0 ;

    return {
        add:function() {
            sum = sum + 1;
            return sum;
        },
        reset:function() {
            return sum = 0;    
        }  
    }   
}());
alert(modularpattern.add());    // alerts: 1
alert(modularpattern.add());    // alerts: 2
alert(modularpattern.reset());  // alerts: 0

jsfiddle pour le code ci-dessus.

L'objectif est de cacher l'accessibilité variable du monde extérieur.

J'espère que cela t'aides. Bonne chance.

kta
la source
serait-il préférable de nommer l'iife? à des fins sémantiques et un meilleur traçage de pile? cela changerait-il quelque chose dans le code?
Jeroen
2
Votre premier exemple (function() { /* Your code goes here */}());est en fait un IIFE (Immediately Invoking Function Expression), ok c'est anonyme car il n'a pas de nom donc vous voudrez peut-être même l'appeler IIAFE (Immediately Invoking Anonymous Function Expression) voir plus sur IIFE sur stackoverflow.com/questions/ 2421911 /…
Adrien Be
pourquoi la déclaration return a-t-elle été utilisée? si nous omettons return {} alors la fonction d'ajout et de réinitialisation serait publique et je suppose qu'ils peuvent accéder à la variable locale sum? ai-je raison?
Mou
votre deuxième exemple ressemble à un objet ou je n'ai pas raison?
The Reason
4
Cela ne répond pas à la question du PO. Il s'agit d'une description du modèle de module et non d'un exemple de la façon dont plusieurs modules peuvent fonctionner ensemble comme le souhaite l'OP.
Erik Trautman le
39

Je recommanderais vraiment à quiconque abordant ce sujet de lire le livre gratuit d'Addy Osmani:

"Apprentissage des modèles de conception JavaScript".

http://addyosmani.com/resources/essentialjsdesignpatterns/book/

Ce livre m'a énormément aidé lorsque j'ai commencé à écrire du JavaScript plus maintenable et je l'utilise toujours comme référence. Jetez un œil à ses différentes implémentations de modèles de modules, il les explique très bien.

Code Noviciat
la source
Je vous recommande également de lire mon article sur le "Definitive Module Pattern" qui n'est pas couvert dans le livre d'Addy Osmani: github.com/tfmontague/definitive-module-pattern
tfmontague
1
Comment cela se compare-t-il à "JavaScript Patterns" de Stoyan Stefanov
JohnMerlino
4
Le livre de Stoyan est beaucoup plus complet. Il couvre plus que de simples modèles de haut niveau, mais aborde également plus en détail d'autres bonnes pratiques JS.
Code Noviciat
1
Commentaires sur "Apprendre les modèles de conception JavaScript" amazon.com/product-reviews/1449331815
Adrien Be
3
critiques de "JavaScript Patterns" par Stoyan Stefanov amazon.com/product-reviews/0596806752 . Note: qui semble bien meilleure que celle de "Learning JavaScript Design Patterns"
Adrien Be
19

J'ai pensé développer la réponse ci-dessus en expliquant comment vous intégriez des modules dans une application. J'avais lu à ce sujet dans le livre de Doug Crockford, mais étant nouveau en javascript, tout était encore un peu mystérieux.

Je viens de fond ac # donc j'ai ajouté une terminologie que je trouve utile à partir de là.

HTML

Vous aurez une sorte de fichier html de premier niveau. Il est utile de considérer cela comme votre fichier de projet. Chaque fichier javascript que vous ajoutez au projet veut y entrer, malheureusement vous n'obtenez pas de support pour cela (j'utilise IDEA).

Vous devez ajouter des fichiers au projet avec des balises de script comme celle-ci:

        <script type="text/javascript" src="app/native/MasterFile.js" /></script>
        <script type="text/javascript" src="app/native/SomeComponent.js" /></script>

Il semble que le fait de réduire les balises fasse échouer les choses - alors que cela ressemble à xml, c'est vraiment quelque chose avec des règles plus folles!

Fichier d'espace de noms

MasterFile.js

myAppNamespace = {};

c'est tout. C'est juste pour ajouter une seule variable globale pour le reste de notre code. Vous pouvez également déclarer des espaces de noms imbriqués ici (ou dans leurs propres fichiers).

Modules)

SomeComponent.js

myAppNamespace.messageCounter= (function(){

    var privateState = 0;

    var incrementCount = function () {
        privateState += 1;
    };

    return function (message) {
        incrementCount();
        //TODO something with the message! 
    }
})();

Ce que nous faisons ici, c'est attribuer une fonction de compteur de messages à une variable dans notre application. C'est une fonction qui renvoie une fonction que nous exécutons immédiatement .

Concepts

Je pense qu'il est utile de penser à la ligne supérieure de SomeComponent comme étant l'espace de noms où vous déclarez quelque chose. La seule mise en garde à cela est que tous vos espaces de noms doivent d'abord apparaître dans un autre fichier - ce ne sont que des objets enracinés par notre variable d'application.

Je n'ai pris que des mesures mineures avec cela pour le moment (je suis en train de refactoriser du javascript normal à partir d'une application extjs afin de pouvoir le tester) mais cela semble assez agréable car vous pouvez définir de petites unités fonctionnelles tout en évitant le bourbier de `` this » .

Vous pouvez également utiliser ce style pour définir des constructeurs en renvoyant une fonction qui renvoie un objet avec une collection de fonctions et en ne l'appelant pas immédiatement.

JonnyRaa
la source
6

Ici https://toddmotto.com/mastering-the-module-pattern, vous pouvez trouver le modèle expliqué en détail. J'ajouterais que la deuxième chose à propos du JavaScript modulaire est de savoir comment structurer votre code en plusieurs fichiers. Beaucoup de gens peuvent vous conseiller ici d'utiliser AMD, mais je peux dire par expérience que vous vous retrouverez sur un certain point avec une réponse de page lente en raison de nombreuses requêtes HTTP. La solution est la pré-compilation de vos modules JavaScript (un par fichier) en un seul fichier suivant la norme CommonJS. Jetez un œil à des exemples ici http://dsheiko.github.io/cjsc/

Dmitry Sheiko
la source
Toutes les implémentations AMD fournissent également une précompilation dans un seul fichier.
I-Lin Kuo
1
C'est correct, mais le fichier optimisé qui en résulte nécessite la bibliothèque de chargement (il suffit de la revérifier avec r.js v2.1.14), ce qui est généralement assez lourd. Dès que nous avons compilé du code, nous n'avons pas besoin de résoudre les dépendances chargées de manière asynchrone, nous n'avons pas besoin de cette bibliothèque. Considérez simplement: nous enveloppons des modules dans AMD, cela signifie asynchrone. chargement, puis compilez-les dans un seul fichier (plus de chargement séparé), mais chargez toute la bibliothèque pour y répondre (ce qui est redondant maintenant). Cela ne me semble pas optimal. Pourquoi AMD du tout lorsque nous ne chargeons pas de manière asynchrone?
Dmitry Sheiko
almond.js fournit un chargeur de poids plus petit pour le code de production fini que RequireJS, mais comparativement, l'avantage en termes de performances de ne pas faire une seule requête http dépasse de loin le coût d'ajout du code de chargeur au module, donc bien qu'il soit moins optimal, il est à une échelle beaucoup plus petite. La question, à mon avis, devrait être retournée - pourquoi supposer la synchronicité alors que le navigateur ne l'est pas? Je suis en fait d'avis que RequireJS et CommonJS devraient avoir une implémentation de promesse intégrée.
I-Lin Kuo
Les deux formats sont des chemins valides vers les modules CommonJS / 2.0 et offrent la même évolutivité. Quant à moi, gérer les modules CJS / 1.1 (c'est ce que j'entends par CommonJS) est beaucoup plus facile, le code semble plus propre.
Dmitry Sheiko
J'ai rencontré des avantages d'AMD tels que: * peut charger plus que de simples fichiers JavaScript; * alias de chemin; Eh bien, CommonJS Compiler les résout - il charge les dépendances non-JavaScipt / JSON en tant que données et peut être fourni avec la configuration de construction (y compris les alias). Le seul inconvénient qu'il nécessite de construire. Mais de nos jours, tout le monde construit de toute façon le projet pour les pré-processeurs CSS. Il s'agit donc simplement d'ajouter une tâche supplémentaire pour Grunt / Gulp ...
Dmitry Sheiko