JavaScript est une langue curieuse. C'est facile à écrire, mais difficile à maîtriser. À la fin de cet article, j'espère que vous transformerez votre code spaghetti en un repas de cinq plats, plein de mets lisibles et maintenables.!
Ce qu’il faut retenir avant tout lors de l’écriture de code JS, c’est qu’il s’agit d’un langage dynamique. Cela signifie qu'il y a beaucoup des façons de faire les choses. Vous n'avez pas à faire face à des classes fortement typées ni à certaines des fonctionnalités plus complexes de langages tels que C # et Java. C'est à la fois une bénédiction et une malédiction.
La "dureté" de JavaScript est clairement évident lorsque l'on considère l'image suivante:
Le livre minuscule à gauche est le livre MUST READ de Douglas Crockford, JavaScript: les bonnes parties. À côté, à droite, se trouve, JavaScript Le Guide Définitif, par David Flanagan.
Bien que ces deux livres constituent d'excellentes lectures, The Good Parts montre que, bien que JavaScript comporte BEAUCOUP d'éléments, les bonnes parties peuvent être résumées dans une lecture beaucoup plus courte. Donc, si vous cherchez une bonne lecture rapide, allez avec The Good Parts - et lisez-le plusieurs fois.!
Cela a naturellement conduit à beaucoup de nuits blanches pour les développeurs web.
Vous pouvez lire un article sur l'histoire de JavaScript ici, mais l'essentiel est que Brandon Eich, en 1995, a été embauché par Netscape pour concevoir un langage. Ce qu'il a trouvé, c'est le langage mal typé que nous connaissons sous le nom de JavaScript. Au fil des ans, il est devenu "standardisé" en tant que ECMAscript, mais, tout au long des guerres de navigateur, les différents navigateurs ont implémenté ces fonctionnalités différemment. Cela a naturellement entraîné beaucoup de nuits blanches pour les développeurs Web. Ce problème, associé au fait que JavaScript était considéré comme le plus approprié pour manipuler des images et effectuer des validations rapides, a conduit JavaScript à être considéré à tort comme un langage terrible..
Il est temps de réparer ça! Bien que, oui, le JavaScript présente de nombreux inconvénients, mais s’il est utilisé correctement, il peut être un langage fantastique - et sa nature dynamique se développera sur vous.!
L’un des inconvénients de la mise en œuvre de JavaScript est qu’il fonctionne au-dessus d’une global objet. Dans le cas des navigateurs, cela finira par être la la fenêtre
objet. Donc, chaque fois que ce code est présent sur une page…
function doStuff () alert ('Je fais des choses'); function doMoreStuff () var images = document.images.length; console.log ("Il y a" + images + "sur cette page"); faire des trucs(); doMoreStuff ();
Les fonctions faire des trucs
et le doMoreStuff
les fonctions sont immédiatement disponibles pour le global la fenêtre
objet.
Cela signifie que si quelqu'un arrive et tente d'écrire une fonction, appelée également, faire des trucs
, il y aura un conflit! Tout scénario
les balises prennent essentiellement le code qu'elles contiennent, et l'exécutent contre le la fenêtre
dans l'ordre dans lequel ils sont référencés dans le code HTML. En conséquence, la deuxième personne à mettre en œuvre faire des trucs
va écraser le premier faire des trucs
.
Une technique courante pour éliminer ce problème consiste à tirer parti des fonctions anonymes auto-exécutables ou des espaces de noms. Les lecteurs orientés objet qui lisent ceci sont probablement déjà familiarisés avec le concept d'espace de nom, mais l'idée de base est de regrouper les fonctions dans différents domaines afin de pouvoir les réutiliser..
var NS = NS || ; // "Si NS n'est pas défini, faites-le égal à un objet vide" NS.Utils = NS.Utils || ; NS.Models = NS.Models || ; NS.Views = NS.Views || ;
Cela évitera la pollution de l’espace de noms global et facilitera la lisibilité de votre application. Maintenant, vous définissez simplement les fonctions dans leur espace de noms respectif. Un espace de noms couramment défini est app
, qui gère le reste de l'application.
Dans chaque langue, il existe un ensemble de modèles de conception. Addy Osmani dit…
Les modèles de conception sont des solutions réutilisables aux problèmes courants de conception de logiciels..
Il y en a beaucoup et, lorsqu'ils sont utilisés correctement, ils peuvent avoir un impact important sur la maintenance de votre application. Addy a écrit un excellent livre de modèles de conception JavaScript, appelé Essential Design Patterns. Absolument lire!
Un autre motif couramment utilisé est le Modèle de module révélateur.
NS.App = (function () // Initialise l'application var init = function () NS.Utils.log ('Application initialisée…');; //; renvoie les méthodes faisant face au public pour l'application. Return init: init; ()); NS.App.init ();
Au dessus, un App
la fonction est définie dans le NS
objet. À l'intérieur, une variable de fonction pour init
est défini et renvoyé en tant que littéral d'objet anonyme. Notez que, à la fin, il y a cet ensemble supplémentaire de parenthèses: ());
. Cela force le NS.App
fonction pour exécuter et revenir automatiquement. Maintenant, vous pouvez appeler NS.App.init ()
pour initialiser votre application.
La fonction anonyme ci-dessus est une meilleure pratique en JavaScript et est appelée une Fonction anonyme à exécution automatique. Étant donné que les fonctions en JavaScript ont leur propre champ d’application (c’est-à-dire que les variables définies à l’intérieur des fonctions ne sont pas disponibles en dehors d’elles), les fonctions anonymes sont utiles de multiples façons..
// Enveloppez votre code dans un SEAF (fonction (global) // Toutes les variables que vous déclarez ici ne sont pas disponibles en dehors de. Var chosePrivate = 'vous ne pouvez pas me joindre!'; Global.somethingPublic = 'mais vous pouvez toutefois accéder à moi! '; (fenêtre)); console.log (window.somethingPublic); // Cela fonctionne… console.log (quelquechose privé); // Erreur
Dans cet exemple, comme cette fonction est exécutée automatiquement, vous pouvez transmettre le la fenêtre
dans la partie d'exécution (la fenêtre));
, et il sera mis à disposition en tant que global
à l'intérieur de la fonction anonyme. Cette pratique limite les variables globales sur le la fenêtre
objet, et aidera à prévenir les collisions de nommage.
Maintenant, vous pouvez commencer à utiliser SEAF dans d'autres zones de votre application pour que le code soit plus modulaire. Cela permet de réutiliser votre code et favorise une bonne séparation des problèmes..
Voici un exemple d'utilisation potentielle de ces idées.
(function ($) var welcomeMessage = 'Bienvenue dans cette application!' NS.Views.WelcomeScreen = function () this.welcome = $ ('# bienvenue');; NS.Views.WelcomeScreen.prototype = showWelcome : function () this.welcome.html (welcomeMessage) .show ();; (jQuery)); $ (function () NS.App.init ();); // Modifie l'application.init ci-dessus var init = function () NS.Utils.log ('Application initialized…'); this.welcome = new NS.Views.WelcomeScreen (); this.welcome.showWelcome (); ;
Donc, ci-dessus, il y a quelques choses différentes qui se passent. d'abord, jQuery
est passé comme argument à la fonction anonyme. Cela garantit que le $
est en fait jQuery à l'intérieur de la fonction anonyme.
Ensuite, il y a une variable privée, appelée message de bienvenue
, et une fonction est assignée à NS.Views.WelcomeScreen
. À l'intérieur de cette fonction, this.welcome
est affecté à un sélecteur DOM jQuery. Ceci met en cache le sélecteur à l'intérieur du Ecran d'accueil
, afin que jQuery n'ait pas à interroger le DOM plus d'une fois.
Les requêtes DOM peuvent nécessiter beaucoup de mémoire. Veillez donc à les mettre en cache autant que possible..
Ensuite, nous emballons l'application init
dans $ (fonction () );
, qui est la même chose que de faire $ (document) .ready ()
.
Enfin, nous ajoutons du code à l'initialiseur de l'application. Cela garde votre code agréable et séparé, et il sera considérablement facile de revenir et de le modifier ultérieurement. Plus de maintenabilité!
Un autre excellent motif est le motif Observer - parfois appelé "Pubsub". Pubsub nous permet essentiellement de souscrire à des événements DOM, tels que Cliquez sur
et passer la souris
. D'une part, nous sommes écoute de l'autre, quelque chose est la publication de ces événements - par exemple, lorsque le navigateur publie (ou annonce) que quelqu'un a cliqué sur un élément particulier. Il y a beaucoup de bibliothèques pour pubsub, car c'est un peu de code. Effectuez une recherche rapide sur Google et des milliers de choix seront disponibles. Un choix solide est la mise en œuvre de AmplifyJS.
// Un modèle de données pour récupérer des nouvelles. NS.Models.News = (function () var newsUrl = '/ news /' // Récupère les informations var getNews = function () $ .ajax (url: newsUrl type: 'get', success: newsRetrieved) ;; var newsRetrieved = function (news) // Publier la récupération des nouvelles amplify.publish ('news-extraites', news);; return getNews: getNews; ());
Ce code définit un modèle pour extraire des nouvelles d'un type de service. Une fois que les nouvelles ont été récupérées avec AJAX, le newsRetrieved
la méthode est déclenchée, passant par les informations récupérées à Amplify, et est publiée sur le sujet extrait,.
(function () // Crée une vue de nouvelles. NS.Views.News = function () this.news = $ ('# news'); // S'abonner à l'événement de récupération de news. amplify.subscribe ('news- retrieved ', $ .proxy (this.showNews));; // Afficher les nouvelles à leur arrivée NS.Views.News.prototype.showNews = function (news) var self = this; $ .each (news, function (article) self.append (article););; ());
Ce code ci-dessus est une vue pour afficher les nouvelles récupérées. dans le Nouvelles
constructeur, Amplify souscrit à la rubrique extraite. Lorsque ce sujet est publié, le showNews
la fonction est déclenchée en conséquence. Ensuite, les nouvelles sont ajoutées au DOM.
// Modifie cela l'application.init ci-dessus var init = function () NS.Utils.log ('Application initialized…'); this.welcome = new NS.Views.WelcomeScreen (); this.welcome.showWelcome (); this.news = new NS.Views.News (); // Va chercher les nouvelles! NS.Models.News.getNews (); ;
Encore une fois, modifiez le init
fonction de l'application pour ajouter la récupération de nouvelles… et vous avez terminé! Maintenant, il existe différentes parties de l'application, chacune d'entre elles étant responsable d'une seule action. Ceci est connu comme le Principe de responsabilité unique.
Une des clés du code maintenable de tout type - pas seulement JS - est documentation et commentaires. Les commentaires peuvent être très utiles aux nouveaux développeurs qui entrent dans un projet, car ils ont besoin de comprendre ce qui se passe dans le code. "Pourquoi est-ce que j’ai encore écrit cette ligne?". Un excellent outil pour générer de la documentation s'appelle Docco. C'est le même outil qui génère la documentation du site Web Backbone.js. Fondamentalement, il prend vos commentaires et les place côte à côte avec votre code.
Il existe également des outils, tels que JSDoc, qui génèrent une documentation de style API, décrivant chaque classe de votre code..
Une autre chose, qui peut s'avérer difficile lors du démarrage d'un nouveau projet, est d'essayer de déterminer la meilleure façon d'organiser votre code. Une solution consiste à séparer les éléments de fonctionnalité dans des dossiers distincts. Par exemple:
Cette structure aide à séparer les éléments de fonctionnalité. Il y a bien sûr plusieurs façons d'organiser le code, mais tout ce qui compte est de choisir une structure… et de la faire avancer ensuite. Ensuite, vous pouvez utiliser un outil de construction et de minification. Il y a beaucoup de choix:
Ces outils supprimeront les espaces, supprimeront les commentaires et combineront tous les fichiers spécifiés en un seul. Cela réduit la taille des fichiers et les requêtes HTTP pour l'application. Mieux encore, cela signifie que vous pouvez garder tous vos fichiers séparés pendant le développement, mais combinés pour la production..
La définition de module asynchrone est une manière différente d'écrire du code JavaScript.
La définition de module asynchrone est une manière différente d’écrire du code JavaScript; il divise tout le code en modules séparés. AMD crée un modèle standard pour écrire ces modules afin de les charger dans le code de manière asynchrone.
En utilisant scénario
Les balises bloquent la page, car elle se charge jusqu'à ce que le DOM soit prêt. Par conséquent, utiliser quelque chose comme AMD permettra au DOM de continuer à se charger, alors que les scripts continuent également à se charger. En gros, chaque module est divisé en son propre fichier, puis un fichier lance le processus. L’implémentation la plus populaire d’AMD est RequireJS..
// main.js require (['libs / jquery', 'app.js']], fonction ($, app) $ (fonction () app.init (););); // app.js define (['libs / jquery', 'views / home']], fonction ($, home) home.showWelcome ();); // home.js define (['libs / jquery'], fonction ($) var home = fonction () this.home = $ ('# home');; home.prototype.showWelcome = function () this.home.html ('Welcome!');; return new home (););
Dans l'extrait de code ci-dessus, il y a un main.js
fichier, qui est l'endroit où le processus commence. Le premier argument à la exiger
fonction est un tableau de dépendances. Ces dépendances constituent une liste de fichiers requis pour app.js
. À la fin du chargement, tout ce que retourne le module est passé en argument à la fonction callback à droite..
Ensuite il y a app.js
, qui nécessite jQuery, ainsi qu'une vue. Ensuite, la vue, home.js
, nécessite uniquement jQuery. Il a un maison
fonctionne en son sein et renvoie une instance de lui-même. Dans votre application, ces modules sont tous stockés dans des fichiers séparés, ce qui rend votre application très facile à gérer..
Garder vos applications maintenables est extrêmement important pour le développement. Cela réduit les bogues et facilite la résolution des problèmes que vous trouvez..
"Les amis ne laissent pas les amis écrire du code spaghetti!"