JavaScript è una lingua curiosa. È facile da scrivere, ma difficile da padroneggiare. Alla fine di questo articolo, si spera, trasformerai il tuo codice spaghetti in un pasto di cinque portate, pieno di bontà leggibile e manutenibile!
La cosa da ricordare, soprattutto quando si scrive codice JS, è che è un linguaggio dinamico. Questo significa che ci sono Un sacco di modi per fare le cose. Non devi occuparti di classi fortemente tipizzate o di alcune delle più complesse funzionalità di linguaggi come C # e Java. Questa è sia una benedizione che una maledizione.
La "durezza" di JavaScript è chiaramente evidente quando si considera la seguente immagine:
Il minuscolo libro sulla sinistra è il libro MUST READ di Douglas Crockford, JavaScript: Le buone parti. Torreggiare accanto ad esso, a destra, è, JavaScript La guida definitiva, di David Flanagan.
Mentre entrambi questi libri sono letture eccellenti, The Good Parts illustra che, sebbene JavaScript abbia un sacco di cose in esso, le parti buone possono essere riassunte in una lettura notevolmente più breve. Quindi, se stai cercando una buona, veloce lettura, vai con The Good Parts - e leggerlo alcune volte!
Questo, naturalmente, ha portato a un sacco di notti insonni per gli sviluppatori web.
Puoi leggere un articolo sulla storia di JavaScript qui, ma il succo è che Brandon Eich, nel 1995, è stato assunto da Netscape per progettare un linguaggio. Ciò che ha inventato è stato il linguaggio vagamente tipizzato che conosciamo come JavaScript. Nel corso degli anni, è diventato "standardizzato" come ECMAscript, ma, durante tutte le guerre del browser, i vari browser hanno implementato queste funzionalità in modo diverso. Questo, naturalmente, porta a un sacco di notti insonni per gli sviluppatori web. Questo problema, quando combinato con il fatto che JavaScript era considerato più applicabile per manipolare le immagini e l'esecuzione di brevi bit di validazione, portava JavaScript a essere erroneamente considerato come un linguaggio terribile.
È ora di aggiustarlo! Mentre, sì, ci sono un sacco di cose brutte su JavaScript, se usato correttamente, può essere un linguaggio fantastico - e la natura dinamica crescerà su di te!
Uno dei fallimenti di come JavaScript è implementato è che funziona in cima a a globale oggetto. Nel caso dei browser, questo finirà per essere il finestra
oggetto. Quindi, ogni volta che il codice come questo è presente su una pagina ...
function doStuff () alert ('Sto facendo cose'); function doMoreStuff () var images = document.images.length; console.log ("Ci sono" + immagini + "in questa pagina"); fare cose(); doMoreStuff ();
Le funzioni fare cose
e il doMoreStuff
le funzioni sono immediatamente disponibili per il globale finestra
oggetto.
Ciò significa che se qualcuno arriva e tenta di scrivere una funzione, che viene anche chiamata, fare cose
, ci sarà un conflitto! Tutti copione
i tag stanno fondamentalmente prendendo il codice al loro interno e lo eseguono contro il finestra
nell'ordine in cui sono referenziati nell'HTML. Di conseguenza, la seconda persona da implementare fare cose
sovrascriverà il primo fare cose
.
Una tecnica comune per eliminare questo problema è sfruttare le funzioni anonime o gli spazi dei nomi autoeseguiti. Le persone orientate agli oggetti che stanno leggendo questo hanno già familiarità con il concetto di spazio dei nomi, ma l'idea di base è raggruppare le funzioni in aree diverse per la riutilizzabilità.
var NS = NS || ; // "Se NS non è definito, renderlo uguale a un oggetto vuoto" NS.Utils = NS.Utils || ; NS.Models = NS.Models || ; NS.Views = NS.Views || ;
Ciò impedirà l'inquinamento dello spazio dei nomi globale e aiuterà la leggibilità della tua applicazione. Ora, si definiscono semplicemente le funzioni nel rispettivo spazio dei nomi. Uno spazio dei nomi comunemente definito è App
, che gestisce il resto dell'applicazione.
In ogni lingua, esiste una serie di modelli di progettazione. Addy Osmani dice ...
I modelli di progettazione sono soluzioni riutilizzabili per i problemi più comuni nella progettazione del software.
Ce ne sono molti e, se utilizzati correttamente, possono avere un impatto significativo sulla manutenibilità dell'applicazione. Addy ha scritto un grande libro di modelli di design JavaScript, chiamato Essential Design Patterns. Assolutamente dargli una lettura!
Un altro schema comunemente usato è il Rivelare il modello del modulo.
NS.App = (function () // Inizializza l'applicazione var init = function () NS.Utils.log ('Applicazione inizializzata ...');; // Restituisce i metodi di confronto pubblico per il ritorno dell'app init: dentro ; ()); NS.App.init ();
Sopra, un App
la funzione è definita all'interno del NS
oggetto. All'interno, una variabile di funzione per dentro
è definito e restituito come un oggetto anonimo letterale. Si noti che, alla fine, c'è quella serie aggiuntiva di parentesi: ());
. Questo costringe il NS.App
funzione per eseguire e restituire automaticamente. Ora puoi chiamare NS.App.init ()
per inizializzare la tua app.
La funzione anonima qui sopra è una best practice in JavaScript e viene chiamata a Funzione anonima autoeseguibile. Perché le funzioni in JavaScript hanno il loro ambito - cioè le variabili definite all'interno delle funzioni non sono disponibili al di fuori di esse - questo rende le funzioni anonime utili in più modi.
// Avvolgi il tuo codice in un SEAF (funzione (globale) // Ora qualsiasi variabile che dichiari qui non è disponibile al di fuori. Var somethingPrivate = 'non puoi raggiungermi!'; Global.somethingPublic = 'ma puoi comunque arrivare a me! '; (finestra)); console.log (window.somethingPublic); // Funziona ... console.log (qualcosaPrivato); // errore
In questo esempio, poiché questa funzione viene eseguita automaticamente, è possibile passare il finestra
nella parte dell'esecuzione (finestra));
, e sarà reso disponibile come globale
all'interno della funzione anonima. Questa pratica limita le variabili globali sul finestra
oggetto e aiuterà a prevenire le collisioni di denominazione.
Ora puoi iniziare a utilizzare SEAF in altre aree dell'applicazione per rendere il codice più modulare. Ciò consente al tuo codice di essere riutilizzabile e promuove una buona separazione delle preoccupazioni.
Ecco un esempio di un potenziale utilizzo di queste idee.
(function ($) var welcomeMessage = 'Benvenuto in questa applicazione!' NS.Views.WelcomeScreen = function () this.welcome = $ ('# welcome');; NS.Views.WelcomeScreen.prototype = showWelcome : function () this.welcome.html (welcomeMessage) .show ();; (jQuery)); $ (function () NS.App.init ();); // Modifica l'app.init sopra var init = function () NS.Utils.log ('Applicazione inizializzata ...'); this.welcome = new NS.Views.WelcomeScreen (); this.welcome.showWelcome (); ;
Quindi, sopra, ci sono alcune cose diverse in corso. in primo luogo, jQuery
viene passato come argomento alla funzione anonima. Questo assicura che il $
è in realtà jQuery all'interno della funzione anonima.
Successivamente, c'è una variabile privata, chiamata messaggio di benvenuto
, e una funzione è assegnata a NS.Views.WelcomeScreen
. All'interno di questa funzione, this.welcome
è assegnato a un selettore DOM jQuery. Questo memorizza il selettore nella cache welcomeScreen
, in modo che jQuery non debba interrogare il DOM per più di una volta.
Le query DOM possono richiedere molta memoria, quindi assicurati di memorizzarle nella cache il più possibile.
Successivamente, avvolgere l'app dentro
entro $ (Function () );
, che è la stessa cosa che fare $ (Document) .ready ()
.
Infine, aggiungiamo del codice all'inizializzatore dell'app. Ciò mantiene il tuo codice piacevole e separato, e sarà molto facile tornare e modificarlo in un secondo momento. Maggiore manutenibilità!
Un altro modello eccellente è il pattern di osservazione - a volte indicato come "Pubsub". Pubsub ci consente essenzialmente di iscriversi agli eventi DOM, come ad esempio clic
e mouseover
. Da una parte, lo siamo ascoltando a questi eventi, e, dall'altro, qualcosa sta pubblicando quegli eventi - per esempio, quando il browser pubblica (o annuncia) che qualcuno ha cliccato su un particolare elemento. Ci sono molte librerie per pubsub, dato che è un po 'di codice. Esegui una rapida ricerca su Google e migliaia di scelte si renderanno disponibili. Una scelta solida è l'implementazione di AmplifyJS.
// Un modello di dati per il recupero delle notizie. NS.Models.News = (function () var newsUrl = '/ news /' // Recupera le notizie var getNews = function () $ .ajax (url: newsUrl type: 'get', success: newsRetrieved) ;; var newsRetrieved = function (news) // Pubblica il recupero delle notizie amplify.publish ('news-retrieved', news); return getNews: getNews; ());
Questo codice definisce un modello per recuperare notizie da qualche tipo di servizio. Una volta che le notizie sono state recuperate con AJAX, il newsRetrieved
il metodo spara, passa attraverso le notizie recuperate ad Amplify e viene pubblicato sull'argomento recuperato dalle notizie.
(function () // Crea una visualizzazione delle news NS.Views.News = function () this.news = $ ('# news'); // Iscriviti all'evento di recupero delle news. amplify.subscribe ('news- recuperato ', $ .proxy (this.showNews));; // Mostra le notizie quando arriva NS.Views.News.prototype.showNews = function (news) var self = this; $ .each (notizie, funzione (articolo) self.append (articolo););; ());
Questo codice sopra è una vista per la visualizzazione delle notizie recuperate. Nel notizia
costruttore, Amplify si iscrive all'argomento recuperato dalle notizie. Quando quell'argomento è pubblicato, il showNews
la funzione è licenziata, di conseguenza. Quindi, le notizie vengono aggiunte al DOM.
// Modifica l'app.init sopra var init = function () NS.Utils.log ('Applicazione inizializzata ...'); this.welcome = new NS.Views.WelcomeScreen (); this.welcome.showWelcome (); this.news = new NS.Views.News (); // Vai a ricevere le notizie! NS.Models.News.getNews (); ;
Di nuovo, modifica il dentro
funzione dall'app per aggiungere il recupero di notizie ... e il gioco è fatto! Ora, ci sono parti separate dell'applicazione, ognuna delle quali è responsabile di una singola azione. Questo è noto come il Principio della singola responsabilità.
Una delle chiavi per mantenere il codice di qualsiasi tipo - non solo JS - lo è documentazione e commenti. I commenti possono essere invalicabili per i nuovi sviluppatori che entrano in un progetto - che devono capire cosa sta succedendo nel codice. "Perché ho scritto di nuovo quella riga?". Si chiama Docco, uno strumento eccellente per generare documentazione. Questo è lo stesso strumento che genera la documentazione per il sito Web Backbone.js. Fondamentalmente, prende i tuoi commenti e li colloca parallelamente al tuo codice.
Esistono anche strumenti, come JSDoc, che generano una documentazione in stile API, descrivendo ogni classe nel codice.
Un'altra cosa, che può rivelarsi difficile all'avvio di un nuovo progetto, è cercare di determinare come organizzare al meglio il codice. Un modo è separare parti di funzionalità in cartelle separate. Per esempio:
Questa struttura aiuta a tenere separati i tratti di funzionalità. Ci sono, ovviamente, diversi modi per organizzare il codice, ma tutto ciò che conta davvero è decidere una struttura ... e poi rotolare con essa. Successivamente, è possibile utilizzare uno strumento di compilazione e minificazione. Ci sono molte scelte:
Questi strumenti elimineranno gli spazi bianchi, rimuoveranno i commenti e combineranno tutti i file specificati in uno solo. Ciò riduce le dimensioni del file e le richieste HTTP per l'applicazione. Ancora meglio, questo significa che è possibile mantenere separati tutti i file durante lo sviluppo, ma combinati per la produzione.
La definizione di modulo asincrono è un modo diverso di scrivere codice JavaScript.
La definizione di modulo asincrono è un modo diverso di scrivere codice JavaScript; divide tutto il codice in moduli separati. AMD crea uno schema standard per scrivere questi moduli per caricare il codice in modo asincrono.
utilizzando copione
i tag bloccano la pagina, mentre viene caricata finché il DOM non è pronto. Pertanto, l'uso di qualcosa come AMD consentirà al DOM di continuare a caricare, mentre gli script sono ancora in fase di caricamento. Essenzialmente, ogni modulo è diviso in un proprio file, e poi c'è un file che dà il via al processo. L'implementazione più popolare di AMD è RequireJS.
// main.js require (['libs / jquery', 'app.js'], function ($, app) $ (function () app.init (););); // app.js define (['libs / jquery', 'views / home'], function ($, home) home.showWelcome ();); // home.js define (['libs / jquery'], function ($) var home = function () this.home = $ ('# home');; home.prototype.showWelcome = function () this.home.html ('Welcome!');; return new home (););
Nel frammento di codice sopra, c'è un main.js
file, che è dove inizia il processo. Il primo argomento per il richiedere
la funzione è una matrice di dipendenze. Queste dipendenze sono un elenco di file richiesti app.js
. Al termine del caricamento, qualunque sia il modulo restituito viene passato come argomento alla funzione callback sulla destra.
Quindi, c'è app.js
, che richiede jQuery, oltre a una vista. Successivamente, la vista, home.js
, richiede solo jQuery. Ha un casa
funzione al suo interno e restituisce un'istanza di se stesso. Nella tua applicazione, questi moduli sono tutti archiviati in file separati, rendendo la tua applicazione molto manutenibile.
Mantenere le vostre applicazioni mantenibili è estremamente importante per lo sviluppo. Riduce i bug e rende più semplice il processo di correzione di quelli che trovi.
"Gli amici non lasciano che gli amici scrivano il codice spaghetti!"