Sleutelprincipes van onderhoudbare JavaScript

JavaScript is een vreemde taal. Het is gemakkelijk om te schrijven, maar moeilijk te beheersen. Aan het einde van dit artikel, hopelijk, transformeert u uw spaghetti-code in een vijfgangendiner, vol leesbare, onderhoudbare lekkernijen!


Waarom is het zo moeilijk?

Het belangrijkste om te onthouden, vooral wanneer je JS-code schrijft, is dat het een dynamische taal is. Dit betekent dat er zijn veel van manieren om dingen te doen. U hoeft niet te werken met sterk getypeerde klassen of een aantal van de meer complexe functies van talen, zoals C # en Java. Dit is zowel een zegen als een vloek.

De "hardheid" van JavaScript is duidelijk zichtbaar bij het beschouwen van de volgende afbeelding:

Het uiterst kleine boek links is het boek MUST READ van Douglas Crockford, JavaScript: de goede delen. Een torenhoog ernaast, aan de rechterkant, is, JavaScript De definitieve gids, door David Flanagan.

Hoewel beide boeken uitstekende leesresultaten zijn, illustreert The Good Parts dat, hoewel JavaScript een heleboel dingen bevat, de goede delen kunnen worden samengevat in een aanzienlijk kortere versie. Dus, als je op zoek bent naar een goede, snelle lees, ga dan met The Good Parts - en lees het een paar keer!

Dit heeft natuurlijk geleid tot veel slapeloze nachten voor webontwikkelaars.

Je kunt hier een artikel over de geschiedenis van JavaScript lezen, maar de kern hiervan is dat Brandon Eich in 1995 door Netscape werd ingehuurd om een ​​taal te ontwerpen. Wat hij bedacht, was de losjes getypte taal die we kennen als JavaScript. In de loop der jaren werd het "gestandaardiseerd" als ECMAscript, maar gedurende alle browseroorlogen hebben de verschillende browsers deze functies anders geïmplementeerd. Dit heeft natuurlijk geleid tot veel slapeloze nachten voor webontwikkelaars. Dit probleem, in combinatie met het feit dat JavaScript het meest geschikt werd geacht voor het manipuleren van afbeeldingen en het uitvoeren van snelle validatiebits, leidde ertoe dat JavaScript ten onrechte werd gezien als een verschrikkelijke taal..

Het is tijd om dat te repareren! Hoewel, ja, er zijn veel slechte dingen over JavaScript, als het correct wordt gebruikt, kan het een fantastische taal zijn - en het dynamische karakter groeit op jou!


Beter maken

namespaces

Een van de nadelen van hoe JavaScript wordt geïmplementeerd, is dat het werkt bovenop een globaal voorwerp. In het geval van browsers wordt dit het venster voorwerp. Dus elke keer als die code zoals deze aanwezig is op een pagina ...

 function doStuff () alert ('Ik doe dingen');  function doMoreStuff () var images = document.images.length; console.log ("Er zijn" + afbeeldingen + "op deze pagina");  dingen doen(); doMoreStuff ();

De functies dingen doen en de doMoreStuff functies zijn onmiddellijk beschikbaar voor de global venster voorwerp.

Dit betekent dat als iemand langskomt en probeert een functie te schrijven, die ook wel wordt genoemd, dingen doen, er zal een conflict zijn! Allemaal script tags nemen in principe de code in zich op en voeren het uit met de venster in de volgorde waarin ernaar wordt verwezen in de HTML. Dientengevolge, de tweede persoon te implementeren dingen doen zal de eerste overschrijven dingen doen.

Een veel gebruikte techniek om dit probleem te verhelpen is om te profiteren van zelfuitvoerende anonieme functies of naamruimten. De object-georiënteerde mensen die dit lezen, zijn waarschijnlijk al bekend met het concept van een naamruimte, maar het basisidee is om functies in verschillende gebieden te groeperen voor herbruikbaarheid.

 var NS = NS || ; // "Als NS niet is gedefinieerd, maakt u het gelijk aan een leeg object" NS.Utils = NS.tils || ; NS.Models = NS.Models || ; NS.Views = NS.Views || ;

Hiermee wordt vervuiling van de algemene naamruimte voorkomen en wordt de leesbaarheid voor uw toepassing verbeterd. Nu definieert u eenvoudig functies in hun respectieve naamruimte. Een algemeen gedefinieerde naamruimte is app, die de rest van de applicatie beheert.

Ontwerppatronen en -praktijken

In elke taal bestaat een reeks ontwerppatronen. Addy Osmani zegt ...

Ontwerppatronen zijn herbruikbare oplossingen voor vaak voorkomende problemen bij het ontwerpen van software.

Er zijn veel, en bij correct gebruik kunnen ze een grote invloed hebben op de onderhoudbaarheid van uw applicatie. Addy heeft een geweldig JavaScript-ontwerppatronenboek geschreven, genaamd Essential Design Patterns. Absoluut geef het een lezen!

Een ander veelgebruikt patroon is de Onthullend modulepatroon.

 NS.App = (function () // Initialiseer de toepassing var init = function () NS.Utils.log ('Application initialized ...');; // Retourneer de openbare methoden voor het retourneren van de app init: in het ; ()); NS.App.init ();

Hierboven, een App functie wordt gedefinieerd binnen de NS voorwerp. Binnenin een functie variabele voor in het is gedefinieerd en geretourneerd als een anoniem object letterlijk. Merk op dat er aan het eind die extra set haakjes is: ());. Dit dwingt de NS.App functie om automatisch uit te voeren en terug te keren. Nu kunt u bellen NS.App.init () om uw app te initialiseren.

De anonieme functie hierboven is een goede gewoonte in JavaScript en wordt a Zelfuitvoerende anonieme functie. Omdat functies in JavaScript hun eigen bereik hebben, dat wil zeggen variabelen gedefinieerd binnen functies, zijn anonieme functies op meerdere manieren niet bruikbaar.

 // Wikkel je code in een SEAF (functie (globaal) // Nu zijn variabelen die je hier declareert niet buiten beschikbaar. Var somethingPrivate = 'je kunt me niet bereiken!'; Global.somethingPublic = 'maar je kunt dit wel mij! '; (venster)); console.log (window.somethingPublic); // Dit werkt ... console.log (somethingPrivate); // Fout

In dit voorbeeld, omdat deze functie automatisch wordt uitgevoerd, kunt u de venster in het uitvoerende gedeelte (venster));, en het zal beschikbaar worden gemaakt als globaal binnenkant van de anonieme functie. Deze praktijk beperkt de globale variabelen op de venster object en helpt bij het voorkomen van botsingen met namen.

Nu kunt u SEAF's in andere delen van uw toepassing gaan gebruiken om de code modulairer te maken. Dit zorgt ervoor dat uw code herbruikbaar is en bevordert een goede scheiding van punten van zorg.

Hier is een voorbeeld van een potentieel gebruik voor deze ideeën.

 (function ($) var welcomeMessage = 'Welkom bij deze applicatie!' NS.Views.WelcomeScreen = function () this.welcome = $ ('# welcome');; NS.Views.WelcomeScreen.prototype = showWelcome : function () this.welcome.html (welcomeMessage) .show ();; (jQuery)); $ (function () NS.App.init ();); // Wijzig de App.init boven var init = function () NS.Utils.log ('Application initialized ...'); this.welcome = new NS.Views.WelcomeScreen (); this.welcome.showWelcome (); ;

Dus, hierboven, er zijn een paar verschillende dingen aan de hand. ten eerste, jQuery wordt doorgegeven als een argument voor de anonieme functie. Dit zorgt ervoor dat de $ is eigenlijk jQuery binnen de anonieme functie.

Vervolgens is er een privévariabele, genaamd Welkoms bericht, en een functie is toegewezen aan NS.Views.WelcomeScreen. Binnen deze functie, this.welcome is toegewezen aan een jQuery DOM-selector. Dit plaatst de selector in de cache welkom scherm, zodat jQuery de DOM er niet meer dan één keer naar hoeft te vragen.

DOM-query's kunnen geheugenintensief zijn, dus zorg ervoor dat u ze zoveel mogelijk in de cache opslaat.

Vervolgens pakken we de app in in het binnen $ (Function () );, dat is hetzelfde als doen $ (Document) .ready ().

Ten slotte voegen we wat code toe aan de app-initialisatie. Hierdoor blijft uw code mooi en gescheiden en is het aanzienlijk eenvoudiger om op een later tijdstip terug te komen en te wijzigen. Meer onderhoudbaarheid!

Waarnemingspatroon

Een ander uitstekend patroon is het waarnemerspatroon - soms aangeduid als "Pubsub." Pubsub stelt ons in wezen in staat om zich te abonneren op DOM-evenementen, zoals Klik en mouseover. Aan de ene kant zijn we dat het luisteren deze gebeurtenissen en aan de andere kant publiceert iets die gebeurtenissen, bijvoorbeeld wanneer de browser publiceert (of aankondigt) dat iemand op een bepaald element heeft geklikt. Er zijn veel bibliotheken voor pubsub, omdat het een klein stukje code is. Voer een snelle Google-zoekopdracht uit en duizenden keuzes maken zichzelf beschikbaar. Een solide keuze is de implementatie van AmplifyJS.

 // Een gegevensmodel voor het ophalen van nieuws. NS.Models.News = (function () var newsUrl = '/ news /' // Ophalen van het nieuws var getNews = function () $ .ajax (url: newsUrl type: 'get', success: newsRetrieved) ;; var newsRetrieved = function (news) // Publiceer het ophalen van het nieuws amplify.publish ('nieuws-opgehaald', nieuws);; return getNews: getNews; ());

Deze code definieert een model om nieuws te halen uit een of andere dienst. Zodra het nieuws is opgehaald met AJAX, is de newsRetrieved methode vuurt, het opgehaalde nieuws doorstuurt naar Amplify en wordt gepubliceerd op het nieuws-opgehaalde onderwerp.

 (function () // Maak een nieuwsoverzicht. NS.Views.News = function () this.news = $ ('# news'); // Abonneer je op de nieuwsherinnering. amplify.subscribe ('news- retrieved ', $ .proxy (this.showNews));; // Laat het nieuws zien wanneer het arriveert NS.Views.News.prototype.showNews = function (news) var self = this; $ .each (nieuws, functie (artikel) self.append (article););; ());

Deze code hierboven is een weergave voor het weergeven van het opgehaalde nieuws. In de Nieuws constructor, Amplify abonneert zich op het nieuws-opgehaalde onderwerp. Wanneer dat onderwerp wordt gepubliceerd, is de Shownieuws de functie wordt dus afgevuurd. Vervolgens wordt het nieuws toegevoegd aan de DOM.

 // Wijzig dit de App.init boven var init = function () NS.Utils.log ('Applicatie geïnitialiseerd ...'); this.welcome = new NS.Views.WelcomeScreen (); this.welcome.showWelcome (); this.news = new NS.Views.News (); // Krijg het nieuws! NS.Models.News.getNews (); ;

Nogmaals, wijzig de in het functie van de app om het ophalen van nieuws toe te voegen ... en je bent klaar! Nu zijn er afzonderlijke delen van de applicatie, die elk verantwoordelijk zijn voor een enkele actie. Dit staat bekend als de Single Responsibility Principle.


Documentatie en bestanden / minificatie

Een van de sleutels tot onderhoudbare code van welke aard dan ook - niet alleen JS - is documentatie en commentaar. Opmerkingen kunnen dienen als zijnde onoverkomelijk voor nieuwe ontwikkelaars die een project binnenkomen - ze moeten begrijpen wat er in de code gebeurt. "Waarom heb ik die regel opnieuw geschreven?". Een uitstekende tool voor het genereren van documentatie wordt Docco genoemd. Dit is dezelfde tool die de documentatie voor de Backbone.js-website genereert. Kortom, het neemt uw opmerkingen op, en plaatst ze naast uw code.

Er zijn ook hulpmiddelen, zoals JSDoc, die een API-stijldocumentatie genereren die elke klasse in uw code beschrijft.

Een ander ding, dat moeilijk kan blijken te zijn bij het starten van een nieuw project, is proberen te bepalen hoe je je code het best kunt organiseren. Eén manier is om stukjes functionaliteit in afzonderlijke mappen te scheiden. Bijvoorbeeld:

  • /app.js
  • /libs/jquery.js
  • /libs/jquery-ui.js
  • /users/user.js
  • /views/home.js

Deze structuur helpt stukjes functionaliteit van elkaar gescheiden te houden. Er zijn natuurlijk verschillende manieren om code te organiseren, maar het enige dat er echt toe doet, is een structuur kiezen ... en er vervolgens mee aan de slag gaan. Vervolgens kunt u een hulpprogramma voor bouwen en miniseren gebruiken. Er zijn veel keuzes:

  • knorren
  • Google Closure
  • JSMin
  • YUI-compressor

Met deze hulpmiddelen verwijdert u witruimte, verwijdert u opmerkingen en combineert u alle opgegeven bestanden tot één. Dit vermindert de bestandsgroottes en HTTP-aanvragen voor de toepassing. Beter nog, dit betekent dat je al je bestanden gescheiden kunt houden tijdens de ontwikkeling, maar dan gecombineerd voor productie.


AMD

Asynchrone Module Definitie is een andere manier om JavaScript-code te schrijven.

Asynchrone Module Definitie is een andere manier om JavaScript-code te schrijven; het verdeelt alle code in afzonderlijke modules. AMD maakt een standaardpatroon voor het schrijven van deze modules om asynchroon in code te laden.

Gebruik makend van script tags blokkeert de pagina, terwijl deze wordt geladen totdat de DOM gereed is. Als u zoiets als AMD gebruikt, kan de DOM doorgaan met laden, terwijl de scripts nog steeds worden geladen. In wezen is elke module verdeeld in zijn eigen bestand en dan is er één bestand dat het proces start. De meest populaire implementatie van AMD is RequireJS.

 // main.js vereist (['libs / jquery', 'app.js'], function ($, app) $ (function () app.init (););); // app.js define (['libs / jquery', 'views / home'], functie ($, home) home.showWelcome ();); // home.js define (['libs / jquery'], functie ($) var home = function () this.home = $ ('# home');; home.prototype.showWelcome = function () this.home.html ('Welcome!');; return new home (););

In het bovenstaande codefragment is er een main.js bestand, dat is waar het proces begint. Het eerste argument voor de vereisen functie is een array van afhankelijkheden. Deze afhankelijkheden zijn een lijst met bestanden die nodig zijn voor app.js. Naarmate ze worden geladen, wordt ongeacht de module geretourneerd een argument gegeven voor de functie terugbellen aan de rechterkant.

Dan is er app.js, die jQuery vereist, evenals een weergave. Vervolgens het uitzicht, home.js, vereist alleen jQuery. Het heeft een huis functie erin, en retourneert een instantie van zichzelf. In uw toepassing worden deze modules allemaal in afzonderlijke bestanden opgeslagen, waardoor uw applicatie zeer onderhoudbaar is.


Conclusie

Het onderhoud van uw applicaties is uiterst belangrijk voor de ontwikkeling. Het vermindert bugs en maakt het proces om fouten te herstellen die je wel gemakkelijker vindt.

"Vrienden laten geen vrienden spaghetti-code schrijven!"