Maison >interface Web >js tutoriel >Explication détaillée de la programmation modulaire Javascript_Connaissances de base
La programmation modulaire est un modèle de programmation Javascript très courant. Cela rend généralement le code plus facile à comprendre, mais il existe de nombreuses bonnes pratiques qui ne sont pas largement connues.
Bases
Commençons par un bref aperçu de quelques modèles modulaires depuis qu'Eric Miraglia (le développeur de YUI) a publié pour la première fois un blog décrivant le modèle modulaire il y a trois ans. Si vous êtes déjà très familier avec ces modes modulaires, vous pouvez ignorer cette section et commencer la lecture à partir du « Mode avancé ».
Fermeture anonyme
C'est la structure de base qui rend tout possible, et c'est aussi la meilleure fonctionnalité de Javascript. Nous allons simplement créer une fonction anonyme et l'exécuter immédiatement. Tout le code s'exécutera dans cette fonction et vivra dans une fermeture qui assure la privatisation, ce qui est suffisant pour rendre les variables de ces fermetures disponibles tout au long du cycle de vie de notre application.
Notez la paire de parenthèses les plus extérieures entourant la fonction anonyme. En raison des caractéristiques du langage Javascript, cette paire de parenthèses est nécessaire. En JavaScript, les instructions commençant par le mot-clé function sont toujours considérées comme des déclarations de fonction. Mettre ce code entre parenthèses indique à l'interpréteur qu'il s'agit d'une expression de fonction.
Import de variables globales
Javascript possède une fonctionnalité appelée variables globales implicites. Peu importe où un nom de variable est utilisé, l'interpréteur suivra la chaîne de portée en arrière pour trouver l'instruction de déclaration var de la variable. Si aucune déclaration var n'est trouvée, la variable est considérée comme une variable globale. Si cette variable est utilisée dans une instruction d'affectation et que la variable n'existe pas, une variable globale sera créée. Cela signifie qu'il est facile d'utiliser ou de créer des variables globales dans des fermetures anonymes. Malheureusement, cela donne lieu à un code extrêmement difficile à maintenir, car il est impossible à l’œil humain de déterminer d’un seul coup d’œil quelles variables sont globales.
Heureusement, notre fonction anonyme offre une solution de contournement simple. En passant simplement des variables globales comme arguments à nos fonctions anonymes, nous obtenons un code plus propre et plus rapide que les variables globales implicites. Voici un exemple :
Export de modules
Parfois, vous souhaitez non seulement utiliser des variables globales, mais également les déclarer pour une utilisation répétée. Nous pouvons le faire facilement en les exportant – via la valeur de retour de la fonction anonyme. Cela permettra de compléter un prototype de base du modèle modulaire, suivi d'un exemple complet :
Notez que nous avons déclaré un module global appelé MODULE, qui possède deux propriétés publiques : une méthode appelée MODULE.moduleMethod et une variable appelée MODULE.moduleProperty. De plus, il maintient un état intégré privé en utilisant des fermetures de fonctions anonymes. Dans le même temps, nous pouvons facilement importer les variables globales dont nous avons besoin et utiliser ce modèle modulaire comme nous l'avons appris précédemment.
Mode avancé
La fondation décrite dans la section ci-dessus est suffisante pour de nombreuses situations, et nous pouvons maintenant développer davantage ce modèle modulaire pour créer des structures plus puissantes et extensibles. Commençons par le module MODULE et introduisons ces modes avancés un par un.
Mode grossissement
C'est une limitation du mode modulaire que le module entier doit être dans un seul fichier. Quiconque a travaillé sur un grand projet comprendra l’intérêt de diviser js en plusieurs fichiers. Heureusement, nous disposons d’une excellente implémentation pour les modules d’amplification. Tout d’abord, nous importons un module, lui ajoutons des propriétés et enfin l’exportons. Voici un exemple : effectuez un zoom avant à partir du MODULE d'origine :
Nous utilisons le mot-clé var pour garantir la cohérence, bien qu'il ne soit pas obligatoire ici. Une fois ce code exécuté, notre module dispose déjà d'une nouvelle méthode publique appelée MODULE.anotherMethod. Le fichier d'amplification conserve également son propre état intégré privé et ses objets importés.
Mode zoom large
Notre exemple ci-dessus nécessite que notre module d'initialisation soit exécuté en premier, puis le module d'amplification peut être exécuté. Bien sûr, parfois cela n'est pas nécessairement nécessaire. L'une des meilleures choses qu'une application Javascript puisse faire pour améliorer les performances est d'exécuter des scripts de manière asynchrone. Nous pouvons créer des modules flexibles en plusieurs parties et leur permettre d'être chargés dans n'importe quel ordre grâce au mode d'agrandissement permissif. Chaque dossier doit être organisé selon la structure suivante :
Dans ce modèle, l'expression var est requise. Notez que si MODULE n'a pas été initialisé, cette instruction d'importation créera MODULE. Cela signifie que vous pouvez utiliser un outil comme LABjs pour charger tous vos fichiers de module en parallèle sans blocage.
Mode zoom serré
Le mode zoom large est génial, mais il impose également certaines limitations à vos modules. Plus important encore, vous ne pouvez pas remplacer en toute sécurité les propriétés d'un module. Vous ne pouvez pas non plus utiliser les propriétés d'autres fichiers lors de l'initialisation (mais vous pouvez les utiliser au moment de l'exécution). Le mode d'amplification serré implique une séquence séquentielle de charges et permet de remplacer les propriétés. Voici un exemple simple (zoom sur notre module d'origine) :
Nous avons remplacé l'implémentation de MODULE.moduleMethod dans l'exemple ci-dessus, mais pouvons conserver une référence à la méthode d'origine si nécessaire.
Clonage et héritage
Ce mode est probablement l’option la moins flexible. Cela rend le code plus propre, mais cela se fait au détriment de la flexibilité. Comme je l'ai écrit ci-dessus, si une propriété est un objet ou une fonction, elle ne sera pas copiée, mais deviendra une seconde référence à l'objet ou à la fonction. Modifier l'un d'entre eux modifiera l'autre en même temps (Note du traducteur : parce qu'ils sont fondamentalement les mêmes !). Ce problème de clonage d'objets peut être résolu grâce au processus de clonage récursif, mais le clonage de fonctions peut ne pas être en mesure de le résoudre. Peut-être que eval peut être utilisé pour le résoudre. Par conséquent, je décris cette méthode dans cet article uniquement par souci d’exhaustivité.
Variables privées entre fichiers
Il existe une limitation majeure à diviser un module en plusieurs fichiers : chaque fichier conserve ses propres variables privées et ne peut pas accéder aux variables privées des autres fichiers. Mais ce problème peut être résolu. Voici un exemple de module permissif qui conserve les variables privées dans les fichiers :
Tous les fichiers peuvent définir des attributs sur leurs variables _private respectives, et il est entendu qu'ils sont accessibles par d'autres fichiers. Une fois ce module chargé, l'application peut appeler MODULE._seal() pour empêcher les appels externes au _private interne. Si le module doit être redimensionné, les méthodes internes de l'un ou l'autre fichier peuvent appeler _unseal() avant de charger le nouveau fichier, et appeler à nouveau _seal() une fois le nouveau fichier exécuté. J'utilise ce modèle au travail aujourd'hui et je n'ai pas vu cette approche ailleurs. Je pense que c'est un modèle très utile, et cela vaut la peine d'écrire un article sur le modèle lui-même.
Sous-module
Notre dernier mode avancé est de loin le plus simple. Il existe de nombreux excellents exemples de création de sous-modules. C'est comme créer un module normal :
Bien que cela puisse paraître simple, je pense que cela vaut la peine de le mentionner ici. Les sous-modules présentent tous les avantages avancés des modules généraux, notamment le mode d'amplification et l'état de privatisation.
Conclusion
La plupart des modes avancés peuvent être combinés pour créer un mode plus utile. Si je devais recommander un modèle modulaire pour concevoir des applications complexes, ce serait une combinaison de modèles d'élargissement indulgents, de variables privées et de sous-modules.
Je n'ai pas réfléchi aux problèmes de performances de ces modèles, mais je préfère traduire cela en une façon de penser plus simple : si un modèle modulaire a de bonnes performances, alors il peut faire un bon travail de minimisation, ce qui rend le téléchargement ce fichier de script plus rapidement. L’utilisation du mode d’amplification indulgent permet des téléchargements parallèles simples et non bloquants, ce qui se traduit par des téléchargements plus rapides. Le temps d'initialisation peut être légèrement plus lent que celui des autres méthodes, mais le compromis en vaut la peine. Tant que les variables globales sont importées correctement, il ne devrait y avoir aucun impact sur les performances d'exécution, et il est possible d'obtenir des vitesses d'exécution plus rapides en raccourcissant les chaînes de référence avec des variables privées dans les sous-modules.
Pour terminer, voici un exemple de sous-module se chargeant dynamiquement dans son module parent (créant le module parent s'il n'existe pas). Par souci de simplicité, j'ai supprimé les variables privées. Bien entendu, l'ajout de variables privées est également très simple. Ce modèle de programmation permet de charger en parallèle toute une base de code hiérarchique complexe via des sous-modules.
Cet article résume les meilleures pratiques actuelles de « programmation modulaire Javascript » et explique comment les mettre en pratique. Bien qu'il ne s'agisse pas d'un didacticiel d'introduction, vous pouvez le comprendre à condition d'avoir un peu de compréhension de la syntaxe de base de Javascript.