Best practice comunemente accettate per l'organizzazione del codice in JavaScript [chiuso]


561

Poiché i framework JavaScript come jQuery rendono le applicazioni Web lato client più ricche e funzionali, ho iniziato a notare un problema ...

Come diavolo ti organizzi?

  • Metti tutti i tuoi gestori in un posto e scrivi le funzioni per tutti gli eventi?
  • Creare funzioni / classi per avvolgere tutte le tue funzionalità?
  • Scrivi come un matto e speri solo che funzioni per il meglio?
  • Rinunciare e ottenere una nuova carriera?

Cito jQuery, ma è davvero qualsiasi codice JavaScript in generale. Sto scoprendo che quando le righe su righe iniziano ad accumularsi, diventa più difficile gestire i file di script o trovare quello che stai cercando. Probabilmente i maggiori problemi che ho trovato è che ci sono molti modi per fare la stessa cosa, è difficile sapere quale sia la migliore pratica attualmente accettata.

Ci sono consigli generali sul modo migliore per mantenere i tuoi file .js belli e ordinati come il resto della tua applicazione? O è solo una questione di IDE? C'è un'opzione migliore là fuori?


MODIFICARE

Questa domanda doveva essere più sull'organizzazione del codice e non sull'organizzazione dei file. Ci sono stati alcuni esempi davvero validi di unione di file o suddivisione dei contenuti.

La mia domanda è: qual è l'attuale modo comunemente accettato delle migliori pratiche per organizzare il tuo codice attuale? Qual è la tua strada, o anche un modo consigliato per interagire con gli elementi della pagina e creare un codice riutilizzabile che non sia in conflitto tra loro?

Alcune persone hanno elencato gli spazi dei nomi che è una buona idea. Quali sono alcuni altri modi, in particolare per quanto riguarda gli elementi nella pagina e mantenere il codice organizzato e ordinato?


qualcuno che in realtà si è preso il tempo di parlare dell'organizzazione del codice stesso, non "solo" quale strumento usa per concatenare e comprimere i suoi file JS: stackoverflow.com/questions/16736483/…
Adrien Be

Risposte:


183

Sarebbe molto più bello se javascript avesse degli spazi dei nomi incorporati, ma trovo che organizzare cose come Dustin Diaz descrive qui mi aiuta molto.

var DED = (function() {

    var private_var;

    function private_method()
    {
        // do stuff here
    }

    return {
        method_1 : function()
            {
                // do stuff here
            },
        method_2 : function()
            {
                // do stuff here
            }
    };
})();

Ho messo diversi "spazi dei nomi" e talvolta singole classi in file separati. Di solito inizio con un file e quando una classe o uno spazio dei nomi diventa abbastanza grande da giustificarlo, lo separo nel suo file. Utilizzare uno strumento per combinare tutti i file per la produzione è anche un'ottima idea.


24
Di solito mi riferisco a questo come "il modo di Crockford". +1 da me
Matt Briggs

4
Puoi anche andare un po 'oltre. Vedi questo link: wait-till-i.com/2007/08/22/…
MKroehnert

4
@MattBriggs altrimenti chiamato module patterne si basa su IIFE pattern.
Adrien, il

Non hai bisogno di esportare le classi in qualche modo? Come viene creato un oggetto dall'esterno di tale modulo? O dovrebbe esserci un metodo createNewSomething()nell'oggetto return, quindi la creazione dell'oggetto avviene esclusivamente all'interno del modulo? Hm ... mi aspetto che le classi (costruttori) siano visibili dall'esterno.
robsch,

@robsch Il suo esempio non accetta alcun parametro, ma la maggior parte lo farebbe. Vedi il mio esempio qui per come di solito viene fatto (TypeScript, ma 99% uguale): repl.it/@fatso83/Module-Pattern-in-TypeScript
oligofren

88

Cerco di evitare di includere javascript con HTML. Tutto il codice è incapsulato in classi e ogni classe è nel suo file. Per lo sviluppo, ho tag <script> separati per includere ogni file js, ma vengono uniti in un unico pacchetto più grande per la produzione per ridurre il sovraccarico delle richieste HTTP.

In genere, avrò un singolo file js 'principale' per ogni applicazione. Quindi, se stavo scrivendo un'applicazione "survey", avrei un file js chiamato "survey.js". Ciò conterrebbe il punto di ingresso nel codice jQuery. Creo riferimenti jQuery durante l'istanza e quindi li passo nei miei oggetti come parametri. Ciò significa che le classi javascript sono "pure" e non contengono alcun riferimento agli ID CSS o ai nomi delle classi.

// file: survey.js
$(document).ready(function() {
  var jS = $('#surveycontainer');
  var jB = $('#dimscreencontainer');
  var d = new DimScreen({container: jB});
  var s = new Survey({container: jS, DimScreen: d});
  s.show();
});

Trovo anche che la convenzione di denominazione sia importante per la leggibilità. Ad esempio: antepongo 'j' a tutte le istanze di jQuery.

Nell'esempio sopra, c'è una classe chiamata DimScreen. (Supponiamo che ciò oscuri lo schermo e faccia apparire una finestra di avviso.) Ha bisogno di un elemento div che può ingrandire per coprire lo schermo, quindi aggiungere una finestra di avviso, quindi passo un oggetto jQuery. jQuery ha un concetto di plug-in, ma sembrava limitativo (ad esempio, le istanze non sono persistenti e non sono accessibili) senza un vero vantaggio. Quindi la classe DimScreen sarebbe una classe javascript standard che utilizza jQuery.

// file: dimscreen.js
function DimScreen(opts) { 
   this.jB = opts.container;
   // ...
}; // need the semi-colon for minimizing!


DimScreen.prototype.draw = function(msg) {
  var me = this;
  me.jB.addClass('fullscreen').append('<div>'+msg+'</div>');
  //...
};

Ho creato alcune applicazioni abbastanza complesse usando questo approccio.


15
Trovo che usare $come prefisso nome variabile sia una pratica più comune, ma potrei sbagliarmi. Quindi, $s = $('...')invece di jS = $('...'), solo una questione di preferenza credo. Interessante, però, poiché la notazione ungherese è considerata un odore di codice. È strano quanto alcune delle mie convenzioni / preferenze del mio codice JavaScript siano diverse dalle mie convenzioni di codifica C # / Java.
Jamiebarrow,

9
@jamie In questo caso non è un odore di codice, è precisamente uno dei pochi casi in cui l'ungherese è buono . Potresti voler leggere questo .
Dan Abramov,

3
@DanAbramov grazie per il link. Devo davvero leggere tutti i blog di Joel, spiega le cose così bene. Merita sicuramente la fama / reputazione che ha. Mi riferirò Systems Hungariancome odore di codice e Apps Hungariancome pratica d'ora in poi :)
jamiebarrow,

Immagino che nel mondo C #, potrebbe anche essere un ottimo articolo per promuoverne l'uso var, ora che ci penso. La maggior parte degli argomenti contro l'uso varè dove non sarai sicuro del "tipo" di ciò che viene restituito, ma immagino che l'argomento dovrebbe essere piuttosto contrario a non conoscere la "classe" di ciò che viene restituito. Se usi App ungherese, non dovresti avere questa preoccupazione ... interessante.
Jamiebarrow,

3
@Marnen: vedo il tuo punto, ma non è inutile come guida per il programmatore. Il prefisso $ mi ricorda di cosa si tratta quando leggo il mio codice in un secondo momento, e quindi aiuta a capire più velocemente.
Sean,

39

È possibile suddividere gli script in file separati per lo sviluppo, quindi creare una versione di "rilascio" in cui raggrupparli tutti insieme ed eseguire YUI Compressor o qualcosa di simile su di esso.


A volte ci sono script javascript non necessari. È inutile inviarli al cliente. Penso che sia necessario inviare solo ciò che è necessario. Ovviamente, per un'app Web che viene utilizzata tutto il giorno, come un'app Intranet, potrebbe essere meglio inviare l'intero batch contemporaneamente, al caricamento della prima pagina.
DOK,

2
La compilazione @DOK dovrebbe includere l'escissione di cose inutilizzate.
aehlke,

Esiste anche un concetto di caricamento lento per cercare di ridurre le esigenze di larghezza di banda, in cui si carica la pagina iniziale e quindi si esegue il caricamento asincrono dei file di script richiesti (come indicato in altre risposte a questa domanda). Tuttavia, ciò potrebbe richiedere più richieste e in realtà potrebbe essere meno utilizzabile. @DOK, se JS è memorizzato nella cache, una richiesta media potrebbe essere migliore di alcune piccole.
Jamiebarrow,

27

Ispirato da post precedenti ho fatto una copia di Rakefile e vendor directory distribuiti con WysiHat (un RTE menzionato da changelog) e ha fatto un paio di modifiche per includere il codice-controllo con JSLint e minification con YUI Compressor .

L'idea è di usare Sprockets (da WysiHat) per unire più JavaScript in un unico file, verificare la sintassi del file unito con JSLint e minimizzarlo con YUI Compressor prima della distribuzione.

Prerequisiti

  • Java Runtime
  • gemma rubino e rastrello
  • Dovresti sapere come inserire un JAR in Classpath

Adesso fallo

  1. Scarica Rhino e inserisci il JAR ("js.jar") nel tuo percorso di classe
  2. Scarica YUI Compressor e inserisci il JAR (build / yuicompressor-xyz.jar) nel tuo percorso di classe
  3. Scarica WysiHat e copia la directory "vendor" nella radice del tuo progetto JavaScript
  4. Scarica JSLint per Rhino e inseriscilo nella directory "vendor"

Ora crea un file chiamato "Rakefile" nella directory principale del progetto JavaScript e aggiungi il seguente contenuto:

require 'rake'

ROOT            = File.expand_path(File.dirname(__FILE__))
OUTPUT_MERGED   = "final.js"
OUTPUT_MINIFIED = "final.min.js"

task :default => :check

desc "Merges the JavaScript sources."
task :merge do
  require File.join(ROOT, "vendor", "sprockets")

  environment  = Sprockets::Environment.new(".")
  preprocessor = Sprockets::Preprocessor.new(environment)

  %w(main.js).each do |filename|
    pathname = environment.find(filename)
    preprocessor.require(pathname.source_file)
  end

  output = preprocessor.output_file
  File.open(File.join(ROOT, OUTPUT_MERGED), 'w') { |f| f.write(output) }
end

desc "Check the JavaScript source with JSLint."
task :check => [:merge] do
  jslint_path = File.join(ROOT, "vendor", "jslint.js")

  sh 'java', 'org.mozilla.javascript.tools.shell.Main',
    jslint_path, OUTPUT_MERGED
end

desc "Minifies the JavaScript source."
task :minify => [:merge] do
  sh 'java', 'com.yahoo.platform.yui.compressor.Bootstrap', '-v',
    OUTPUT_MERGED, '-o', OUTPUT_MINIFIED
end

Se hai fatto tutto correttamente, dovresti essere in grado di utilizzare i seguenti comandi nella tua console:

  • rake merge - per unire diversi file JavaScript in uno solo
  • rake check- per verificare la sintassi del codice (questa è l' attività predefinita , quindi puoi semplicemente digitare rake)
  • rake minify - per preparare la versione ridotta del tuo codice JS

Unione alla fonte

Utilizzando Sprockets, il pre-processore JavaScript è possibile includere (o require) altri file JavaScript. Utilizzare la sintassi seguente per includere altri script dal file iniziale (denominato "main.js", ma è possibile modificarlo nel Rakefile):

(function() {
//= require "subdir/jsfile.js"
//= require "anotherfile.js"

    // some code that depends on included files
    // note that all included files can be in the same private scope
})();

E poi...

Dai un'occhiata a Rakefile fornito con WysiHat per configurare il test automatico dell'unità. Bella roba :)

E ora per la risposta

Questo non risponde molto bene alla domanda originale. Lo so e mi dispiace, ma l'ho pubblicato qui perché spero che possa essere utile a qualcun altro organizzare il loro pasticcio.

Il mio approccio al problema è quello di fare quanta più modellazione orientata agli oggetti possibile e separare le implementazioni in diversi file. Quindi i gestori dovrebbero essere il più corti possibile. Anche l'esempio con Listsingleton è bello.

E gli spazi dei nomi ... beh, possono essere imitati da una struttura di oggetti più profonda.

if (typeof org === 'undefined') {
    var org = {};
}

if (!org.hasOwnProperty('example')) {
    org.example = {};
}

org.example.AnotherObject = function () {
    // constructor body
};

Non sono un grande fan delle imitazioni, ma questo può essere utile se hai molti oggetti che vorresti spostare fuori dall'ambito globale.


18

L'organizzazione del codice richiede l'adozione di convenzioni e standard di documentazione:
1. Codice dello spazio dei nomi per un file fisico;

Exc = {};


2. Raggruppare le classi in questi spazi dei nomi javascript;
3. Impostare prototipi o funzioni o classi correlate per rappresentare oggetti del mondo reale;

Exc = {};
Exc.ui = {};
Exc.ui.maskedInput = function (mask) {
    this.mask = mask;
    ...
};
Exc.ui.domTips = function (dom, tips) {
    this.dom = gift;
    this.tips = tips;
    ...
};


4. Impostare convenzioni per migliorare il codice. Ad esempio, raggruppare tutte le sue funzioni o metodi interni nell'attributo class di un tipo di oggetto.

Exc.ui.domTips = function (dom, tips) {
    this.dom = gift;
    this.tips = tips;
    this.internal = {
        widthEstimates: function (tips) {
            ...
        }
        formatTips: function () {
            ...
        }
    };
    ...
};


5. Prepara la documentazione di spazi dei nomi, classi, metodi e variabili. Se necessario, discutere anche del codice (alcuni FI e Fors, di solito implementano una logica importante del codice).

/**
  * Namespace <i> Example </i> created to group other namespaces of the "Example".  
  */
Exc = {};
/**
  * Namespace <i> ui </i> created with the aim of grouping namespaces user interface.
  */
Exc.ui = {};

/**
  * Class <i> maskdInput </i> used to add an input HTML formatting capabilities and validation of data and information.
  * @ Param {String} mask - mask validation of input data.
  */
Exc.ui.maskedInput = function (mask) {
    this.mask = mask;
    ...
};

/**
  * Class <i> domTips </i> used to add an HTML element the ability to present tips and information about its function or rule input etc..
  * @ Param {String} id - id of the HTML element.
  * @ Param {String} tips - tips on the element that will appear when the mouse is over the element whose identifier is id <i> </i>.
  */
  Exc.ui.domTips = function (id, tips) {
    this.domID = id;
    this.tips = tips;
    ...
};


Questi sono solo alcuni suggerimenti, ma ciò ha aiutato molto nell'organizzazione del codice. Ricorda che devi avere disciplina per avere successo!


13

Seguire buoni principi di progettazione OO e schemi di progettazione può fare molto per rendere il codice facile da mantenere e comprendere. Ma una delle cose migliori che ho scoperto di recente sono i segnali e gli slot, ovvero pubblicare / abbonarsi. Dai un'occhiata a http://markdotmeyer.blogspot.com/2008/09/jquery-publish-subscribe.html per una semplice implementazione di jQuery.

L'idea è ben utilizzata in altre lingue per lo sviluppo della GUI. Quando succede qualcosa di significativo da qualche parte nel tuo codice, pubblichi un evento sintetico globale a cui possono iscriversi altri metodi in altri oggetti. Ciò consente un'eccellente separazione degli oggetti.

Penso che Dojo (e Prototype?) Abbiano una versione integrata di questa tecnica.

vedi anche Cosa sono i segnali e gli slot?


L'ho fatto in jQuery. JS ha un modello di eventi integrato, quindi non hai davvero bisogno di molto supporto per il framework.
Marnen Laibow-Koser,

12

Sono stato in grado di applicare con successo il modello di modulo Javascript a un'applicazione Ext JS nel mio precedente lavoro. Ha fornito un modo semplice per creare codice ben incapsulato.


11

Dojo aveva il sistema di moduli sin dal primo giorno. In effetti è considerata una pietra angolare del Dojo, la colla che tiene tutto insieme:

L'utilizzo dei moduli Dojo raggiunge i seguenti obiettivi:

  • Spazi dei nomi per codice Dojo e codice personalizzato ( dojo.declare()): non inquinare lo spazio globale, coesistere con altre librerie e codice non consapevole dell'utente Dojo.
  • Caricamento dei moduli in modo sincrono o asincrono per nome ( dojo.require()).
  • Build personalizzati analizzando le dipendenze dei moduli per creare un singolo file o un gruppo di file interdipendenti (i cosiddetti layer) per includere solo ciò di cui l'applicazione web ha bisogno. Le build personalizzate possono includere anche moduli Dojo e moduli forniti dal cliente.
  • Accesso trasparente basato su CDN a Dojo e al codice utente. Sia AOL che Google portano Dojo in questo modo, ma alcuni clienti lo fanno anche per le loro applicazioni web personalizzate.

9

Dai un'occhiata a JavasciptMVC .

Puoi :

  • suddividere il codice in livelli di modello, visualizzazione e controller.

  • comprimere tutto il codice in un singolo file di produzione

  • generare automaticamente il codice

  • creare ed eseguire test unitari

  • e molto altro...

Soprattutto, utilizza jQuery, quindi puoi sfruttare anche altri plug-in jQuery.


Sì, ho usato jmvc ed è abbastanza buono - i documenti potrebbero essere migliori però
meouw

9

Il mio capo parla ancora dei tempi in cui hanno scritto il codice modulare (linguaggio C) e si lamenta di quanto sia scadente il codice al giorno d'oggi! Si dice che i programmatori possano scrivere assembly in qualsiasi framework. Esiste sempre una strategia per superare l'organizzazione del codice. Il problema di base è con i ragazzi che trattano java script come un giocattolo e non provano mai ad impararlo.

Nel mio caso, scrivo i file js su un tema dell'interfaccia utente o sulla base della schermata dell'applicazione, con un init_screen () appropriato. Utilizzando la convenzione di denominazione id corretta, mi assicuro che non vi siano conflitti di spazio dei nomi a livello di elemento radice. In un window.load () discreto, lego le cose in base all'ID di livello superiore.

Uso rigorosamente le chiusure e i pattern degli script java per nascondere tutti i metodi privati. Dopo aver fatto ciò, non ho mai avuto problemi di proprietà / definizioni di funzioni / definizioni di variabili in conflitto. Tuttavia, quando si lavora con una squadra è spesso difficile applicare lo stesso rigore.


9

Sono sorpreso che nessuno abbia menzionato i framework MVC. Sto usando Backbone.js per modulare e disaccoppiare il mio codice, ed è stato prezioso.

Ci sono alcuni di questi tipi di framework là fuori, e la maggior parte di essi sono anche piuttosto piccoli. La mia opinione personale è che se hai intenzione di scrivere più di un paio di righe di jQuery per elementi dell'interfaccia utente appariscenti, o se desideri una ricca applicazione Ajax, un framework MVC renderà la tua vita molto più semplice.


8

"Scrivi come un matto e speri solo che funzioni al meglio?", Ho visto un progetto come questo che è stato sviluppato e gestito da solo 2 sviluppatori, una grande applicazione con un sacco di codice javascript. Inoltre, c'erano diverse scorciatoie per ogni possibile funzione jquery che ti viene in mente. Ho suggerito di organizzare il codice come plugin, poiché questo è l'equivalente jquery di classe, modulo, spazio dei nomi ... e l'intero universo. Ma le cose sono peggiorate molto, ora hanno iniziato a scrivere plugin sostituendo ogni combinazione di 3 righe di codice utilizzate nel progetto. Personalmente penso che jQuery sia il diavolo e non dovrebbe essere usato su progetti con molti javascript perché ti incoraggia a essere pigro e non pensare ad organizzare il codice in alcun modo. Preferirei leggere 100 righe di javascript piuttosto che una riga con 40 funzioni jQuery concatenate (I ' non sto scherzando). Contrariamente alla credenza popolare, è molto facile organizzare il codice javascript in equivalenti a spazi dei nomi e classi. Questo è ciò che fanno YUI e Dojo. Puoi farlo facilmente, se vuoi. Trovo che l'approccio di YUI sia molto migliore ed efficiente. Ma di solito hai bisogno di un bel editor con supporto per frammenti per compensare le convenzioni di denominazione YUI se vuoi scrivere qualcosa di utile.


3
Concordo con te su comandi concatenati molto lunghi, ma una delle parti migliori di jQuery è che mantiene tutto Javascript fuori dall'HTML. Puoi impostare i gestori di eventi per tutti i tuoi elementi senza "bisogno" di aggiungere ID o eventi <whatever> sui tuoi elementi. Come sempre, l'uso eccessivo di qualsiasi strumento è negativo ...
Hugoware,

Ho lavorato a progetti enormi e ben organizzati in jQuery. Non so perché pensi che interferisca con l'organizzazione.
Marnen Laibow-Koser,

7

Creo singoli per ogni cosa di cui non ho davvero bisogno per istanziare più volte sullo schermo, una lezione per tutto il resto. E tutti vengono inseriti nello stesso spazio dei nomi nello stesso file. Tutto è commentato e progettato con UML, diagrammi di stato. Il codice javascript è privo di HTML, quindi nessun javascript in linea e tendo a usare jquery per ridurre al minimo i problemi tra browser.


3
un buon commento è CHIAVE - Sono contento che tu l'abbia detto, quindi non ho dovuto. Aggiungerei convenzioni di denominazione coerenti, una sorta di strategia organizzativa facilmente comprensibile per variabili e amp; funzioni e, come hai detto, un uso giudizioso delle lezioni rispetto ai singoli.
Matt Lohkamp,

No. Se hai bisogno di commenti, il tuo codice non è generalmente abbastanza leggibile. Cerca di scrivere codice che non abbia bisogno di commenti.
Marnen Laibow-Koser,

Inoltre, se hai bisogno di UML e diagrammi di stato, ciò probabilmente significa che la tua architettura non è abbastanza chiara dal codice. Downvoting.
Marnen Laibow-Koser,

1
@Marnen I progetti ben scritti includono commenti per descrivere PERCHÉ, non necessariamente COSA. Il codice descrive già il WHAT, ma spesso è necessario qualcosa per descrivere il WHY. Upvoting.
Cypher

@Cypher I progetti ben scritti hanno un codice abbastanza chiaro che di solito puoi dire il "perché", non solo il "cosa". Non mi fiderei di un commento per dirmi il "perché", perché non ho alcuna garanzia che sia sincronizzato con il codice. Consenti al codice di documentarsi.
Marnen Laibow-Koser,

6

Nel mio ultimo progetto -Viajeros.com ho usato una combinazione di diverse tecniche. Non saprei come organizzare un'app Web: Viajeros è un sito di social network per viaggiatori con sezioni ben definite, quindi è abbastanza facile separare il codice per ogni area.

Uso la simulazione dello spazio dei nomi e il caricamento lento dei moduli secondo la sezione del sito. Su ogni caricamento di pagina dichiaro un oggetto "vjr" e carico sempre un insieme di funzioni comuni (vjr.base.js). Quindi ogni pagina HTML decide quali moduli sono necessari con un semplice:

vjr.Required = ["vjr.gallery", "vjr.comments", "vjr.favorites"];

Vjr.base.js ottiene ognuno decompresso dal server e li esegue.

vjr.include(vjr.Required);
vjr.include = function(moduleList) {
  if (!moduleList) return false;
  for (var i = 0; i < moduleList.length; i++) {
    if (moduleList[i]) {
      $.ajax({
        type: "GET", url: vjr.module2fileName(moduleList[i]), dataType: "script"
      });
    }
  }
};

Ogni "modulo" ha questa struttura:

vjr.comments = {}

vjr.comments.submitComment = function() { // do stuff }
vjr.comments.validateComment = function() { // do stuff }

// Handlers
vjr.comments.setUpUI = function() {
    // Assign handlers to screen elements
}

vjr.comments.init = function () {
  // initialize stuff
    vjr.comments.setUpUI();
}

$(document).ready(vjr.comments.init);

Data la mia limitata conoscenza di Javascript, so che ci devono essere modi migliori per gestirlo, ma fino ad ora funziona alla grande per noi.


6

L'organizzazione del codice in un modo NameSpace incentrato su Jquery può apparire come segue ... e non si scontrerà con altre API Javascript come Prototype, Ext.

<script src="jquery/1.3.2/jquery.js" type="text/javascript"></script>
<script type="text/javascript">

var AcmeJQ = jQuery.noConflict(true);
var Acme = {fn: function(){}};

(function($){

    Acme.sayHi = function()
    {
        console.log('Hello');
    };

    Acme.sayBye = function()
    {
        console.log('Good Bye');
    };
})(AcmeJQ);

// Usage
//          Acme.sayHi();
// or
// <a href="#" onclick="Acme.sayHi();">Say Hello</a>


</script>

Spero che sia di aiuto.


Questo mi sembra un po 'cult-cargo. jQuery.fnè un puntatore a jQuery.prototype, perché in $()realtà restituisce una nuova istanza della funzione di costruzione jQuery. Aggiungere un 'plugin' a jQuery significa semplicemente estendere il suo prototipo. Ma quello che stai facendo non è quello, e ci sono modi più puliti per ottenere la stessa cosa.
Adam Lassek,

Credo che stia semplicemente creando funzioni statiche. Ricordo di aver visto nei documenti di jQuery che questo modo di dichiarare le funzioni statiche è accettabile
Alex Heyd,

6

Un buon preside di OO + MVC farebbe sicuramente molto per la gestione di un'app javascript complessa.

Fondamentalmente sto organizzando la mia app e javascript al seguente design familiare (che esiste fin dai miei giorni di programmazione desktop al Web 2.0)

JS OO e MVC

Descrizione per i valori numerici sull'immagine:

  1. Widget che rappresentano le visualizzazioni della mia applicazione. Questo dovrebbe essere estensibile e separato ordinatamente, risultando in una buona separazione che MVC cerca di ottenere piuttosto che trasformare il mio widget in un codice spaghetti (equivalente in un'app Web di mettere un grosso blocco di Javascript direttamente in HTML). Ogni widget comunica tramite altri ascoltando l'evento generato da altri widget, riducendo così il forte accoppiamento tra widget che potrebbero portare a codice ingestibile (ricordi il giorno in cui aggiungi onclick ovunque indicando una funzione globale nel tag dello script? Urgh ...)
  2. Modelli di oggetti che rappresentano i dati che voglio popolare nei widget e che vanno avanti e indietro sul server. Incapsulando i dati nel suo modello, l'applicazione diventa agnostica del formato dei dati. Ad esempio: mentre naturalmente in Javascript questi modelli di oggetti sono per lo più serializzati e deserializzati in JSON, se in qualche modo il server utilizza XML per la comunicazione, tutto ciò che devo cambiare è cambiare il livello di serializzazione / deserializzazione e non deve necessariamente cambiare tutte le classi dei widget .
  3. Classi di controller che gestiscono la logica aziendale e la comunicazione con il server + livello di memorizzazione nella cache occasionale. Questo livello controlla il protocollo di comunicazione con il server e inserisce i dati necessari nei modelli di oggetti
  4. Le classi sono disposte ordinatamente nei rispettivi spazi dei nomi. Sono sicuro che tutti sappiamo quanto brutto sia lo spazio dei nomi globale in Javascript.

In passato, avrei separato i file nei suoi js e avrei usato la pratica comune per creare principi OO in Javascript. Il problema che ho scoperto presto che ci sono diversi modi per scrivere JS OO e non è necessariamente che tutti i membri del team abbiano lo stesso approccio. Man mano che il team diventa più grande (nel mio caso più di 15 persone), questo diventa complicato in quanto non esiste un approccio standard per Javascript orientato agli oggetti. Allo stesso tempo, non voglio scrivere il mio framework e ripetere alcune delle opere che sono sicuramente più intelligenti delle persone che ho risolto.

jQuery è incredibilmente bello come Javascript Framework e lo adoro, tuttavia, man mano che il progetto si ingrandisce, ho chiaramente bisogno di una struttura aggiuntiva per la mia app Web, soprattutto per facilitare la pratica OO standardizzata. Per quanto mi riguarda, dopo diversi esperimenti, ho scoperto che l'infrastruttura YUI3 Base e Widget ( http://yuilibrary.com/yui/docs/widget/ e http://yuilibrary.com/yui/docs/base/index.html ) fornisce esattamente quello di cui ho bisogno. Pochi motivi per cui li uso.

  1. Fornisce supporto per lo spazio dei nomi. Un vero bisogno di OO e di una buona organizzazione del codice
  2. Supporta la nozione di classi e oggetti
  3. Fornisce un mezzo standardizzato per aggiungere variabili di istanza alla tua classe
  4. Supporta ordinatamente l'estensione della classe
  5. Fornisce costruttore e distruttore
  6. Fornisce il rendering e l'associazione di eventi
  7. Ha un framework di widget di base
  8. Ogni widget ora è in grado di comunicare tra loro utilizzando un modello basato su eventi standard
  9. Ancora più importante, offre a tutti gli ingegneri uno standard OO per lo sviluppo di Javascript

Contrariamente a molte visualizzazioni, non devo necessariamente scegliere tra jQuery e YUI3. Questi due possono coesistere pacificamente. Mentre YUI3 fornisce il modello OO necessario per la mia complessa app Web, jQuery fornisce comunque al mio team JS Abstraction di facile utilizzo che tutti noi amiamo e conosciamo.

Usando YUI3, sono riuscito a creare un modello MVC separando le classi che estendono la Base come Modello, classi che estendono Widget come Vista e, naturalmente, ci sono classi Controller che stanno effettuando le logiche necessarie e le chiamate lato server.

I widget possono comunicare tra loro utilizzando il modello basato su eventi e ascoltando l'evento e eseguendo l'attività necessaria in base all'interfaccia predefinita. In poche parole, mettere la struttura OO + MVC su JS è una gioia per me.

Solo un disclaimer, non lavoro per Yahoo! e semplicemente un architetto che sta cercando di affrontare lo stesso problema posto dalla domanda originale. Penso che se qualcuno trovasse un framework OO equivalente, anche questo funzionerebbe. Principalmente, questa domanda si applica anche ad altre tecnologie. Grazie a Dio per tutte le persone che hanno ideato OO Principles + MVC per rendere più gestibili le nostre giornate di programmazione.


5

Uso la gestione dei pacchetti ( dojo.requiree dojo.provide) di Dojo e il sistema di classi ( dojo.declareche consente anche l'ereditarietà multipla semplice) per modulare tutte le mie classi / widget in file separati. Non solo dosare ciò per mantenere organizzato il codice, ma consente anche di caricare le classi / i widget in modo pigro / just in time.


3

Qualche giorno fa, i ragazzi di 37Signals hanno rilasciato un controllo RTE , con una svolta. Hanno creato una libreria che raggruppa i file JavaScript utilizzando una sorta di comandi pre-processore.

Lo uso da allora per separare i miei file JS e poi alla fine unirli come uno. In questo modo posso separare le preoccupazioni e, alla fine, ho solo un file che passa attraverso la pipe (compresso, non meno).

Nei tuoi modelli, controlla se sei in modalità di sviluppo e includi i file separati e, se in produzione, includi quello finale (che dovrai "costruire" da solo).


1
getsprockets.org è il collegamento diretto
Matt Gardner,

3

Crea classi false e assicurati che tutto ciò che può essere gettato in una funzione separata che abbia un senso sia fatto. Assicurati anche di commentare molto e di non scrivere il codice spagghetti, piuttosto di tenerlo tutto in sezioni. Ad esempio, un codice senza senso che descrive i miei ideali. Ovviamente nella vita reale scrivo anche molte librerie che sostanzialmente comprendono la loro funzionalità.

$(function(){
    //Preload header images
    $('a.rollover').preload();

    //Create new datagrid
    var dGrid = datagrid.init({width: 5, url: 'datalist.txt', style: 'aero'});
});

var datagrid = {
    init: function(w, url, style){
        //Rendering code goes here for style / width
        //code etc

        //Fetch data in
        $.get(url, {}, function(data){
            data = data.split('\n');
            for(var i=0; i < data.length; i++){
                //fetching data
            }
        })
    },
    refresh: function(deep){
        //more functions etc.
    }
};


2

Penso che questo si leghi, forse, al DDD (Domain-Driven Design). L'applicazione a cui sto lavorando, sebbene priva di un'API formale, fornisce suggerimenti su questo tramite il codice lato server (nomi di classe / file, ecc.). A parte questo, ho creato un oggetto di livello superiore come contenitore per l'intero dominio problematico; quindi, ho aggiunto gli spazi dei nomi dove necessario:

var App;
(function()
{
    App = new Domain( 'test' );

    function Domain( id )
    {
        this.id = id;
        this.echo = function echo( s )
        {
            alert( s );
        }
        return this;
    }
})();

// separate file
(function(Domain)
{
    Domain.Console = new Console();

    function Console()
    {
        this.Log = function Log( s )
        {
            console.log( s );
        }
        return this;
    }
})(App);

// implementation
App.Console.Log('foo');

2

Per l'organizzazione JavaScript è stato utilizzato quanto segue

  1. Cartella per tutto il tuo javascript
  2. JavaScript a livello di pagina ottiene il proprio 'file con lo stesso nome della pagina. ProductDetail.aspx sarebbe ProductDetail.js
  3. All'interno della cartella javascript per i file della libreria ho una cartella lib
  4. Inserisci le funzioni di libreria correlate in una cartella lib che desideri utilizzare in tutta l'applicazione.
  5. Ajax è l'unico javascript che mi sposto fuori dalla cartella javascript e ottiene la sua cartella. Quindi aggiungo due sottocartelle client e server
  6. La cartella client ottiene tutti i file .js mentre la cartella server ottiene tutti i file lato server.

Bello per l'organizzazione dei file. Lo faccio con il codice. Ma alla fine compilo il mio codice in un ... diciamo dll. Ne hai bisogno anche con JavaScript o finirai per richiedere 15 file js per pagina.
Graffic

Non c'è niente di sbagliato nel richiedere 15 file JS per pagina. Il tuo browser li memorizzerà comunque nella cache per le richieste successive.
Marnen Laibow-Koser,

@ MarnenLaibow-Koser L'unico problema con la richiesta di 15 file JS su una pagina è il numero di richieste HTTP che il browser può gestire contemporaneamente. Quindi raggruppandoli in un unico file consente al browser di richiedere contemporaneamente altri file necessari.
ucciso l'

È vero, ma dopo i primi due hit, saranno nella cache del browser, quindi non richiederanno connessioni HTTP.
Marnen Laibow-Koser,

2

Sto usando questa piccola cosa. Ti dà la direttiva "include" sia per i modelli JS che per quelli HTML. Elimina completamente il casino.

https://github.com/gaperton/include.js/

$.include({
    html: "my_template.html" // include template from file...
})
.define( function( _ ){ // define module...
    _.exports = function widget( $this, a_data, a_events ){ // exporting function...
        _.html.renderTo( $this, a_data ); // which expands template inside of $this.

        $this.find( "#ok").click( a_events.on_click ); // throw event up to the caller...
        $this.find( "#refresh").click( function(){
            widget( $this, a_data, a_events ); // ...and update ourself. Yep, in that easy way.
        });
    }
});

2

È possibile utilizzare jquery mx (utilizzato in javascriptMVC) che è un insieme di script che consente di utilizzare modelli, viste e controller. L'ho usato in un progetto e mi ha aiutato a creare javascript strutturato, con dimensioni di script minime a causa della compressione. Questo è un esempio di controller:

$.Controller.extend('Todos',{
  ".todo mouseover" : function( el, ev ) {
   el.css("backgroundColor","red")
  },
  ".todo mouseout" : function( el, ev ) {
   el.css("backgroundColor","")
  },
  ".create click" : function() {
   this.find("ol").append("<li class='todo'>New Todo</li>"); 
  }
})

new Todos($('#todos'));

Puoi anche usare solo il lato controller di jquerymx se non sei interessato alla vista e alle parti del modello.


1

La tua domanda è quella che mi ha afflitto alla fine dell'anno scorso. La differenza: passare il codice a nuovi sviluppatori che non avevano mai sentito parlare di metodi pubblici e privati. Ho dovuto costruire qualcosa di semplice.

Il risultato finale è stato un piccolo framework (circa 1 KB) che traduce i letterali degli oggetti in jQuery. La sintassi è visivamente più facile da scansionare e se il tuo js diventa davvero grande puoi scrivere query riutilizzabili per trovare cose come selettori usati, file caricati, funzioni dipendenti, ecc.

Pubblicare un piccolo framework qui non è pratico, quindi ho scritto un post sul blog con esempi (il mio primo. È stata un'avventura!). Sei il benvenuto a dare un'occhiata.

Per tutti gli altri qui con pochi minuti per verificarlo, apprezzerei molto il feedback!

FireFox consigliato poiché supporta toSource () per l'esempio di query sull'oggetto.

Saluti!

Adamo


0

Uso una sceneggiatura personalizzata ispirata al comportamento di Ben Nolan (purtroppo non riesco a trovare un collegamento attuale a questo) per archiviare la maggior parte dei gestori di eventi. Questi gestori di eventi sono attivati ​​dagli elementi className o Id, ad esempio. Esempio:

Behaviour.register({ 
    'a.delete-post': function(element) {
        element.observe('click', function(event) { ... });
    },

    'a.anotherlink': function(element) {
        element.observe('click', function(event) { ... });
    }

});

Mi piace includere al volo la maggior parte delle mie librerie Javascript, ad eccezione di quelle che contengono comportamenti globali. Per questo uso l'helper segnaposto headScript () di Zend Framework , ma puoi anche usare javascript per caricare altri script al volo con Ajile, ad esempio.


È questo quello che stavi cercando? koders.com/javascript/…
DOK,

Sì, questo è quello! :) Sembra che il codice dietro il link sia piuttosto nuovo rispetto alla versione a cui mi sono ispirato, però. Grazie per i tuoi sforzi!
Aron Rotteveel,

0

Non dici quale sia la tua lingua lato server. O, più pertinentemente, quale framework stai utilizzando, se presente, sul lato server.

IME, organizzo le cose sul lato server e lascio che tutto si agiti sulla pagina web. Al framework viene assegnato il compito di organizzare non solo JS che ogni pagina deve caricare, ma anche frammenti JS che funzionano con il markup generato. Tali frammenti di solito non si desidera emettere più di una volta, motivo per cui vengono astratti nel framework affinché quel codice si occupi di quel problema. :-)

Per le pagine finali che devono emettere il proprio JS, di solito scopro che esiste una struttura logica nel markup generato. Tale JS localizzato può spesso essere assemblato all'inizio e / o alla fine di tale struttura.

Nota che nulla di tutto ciò ti assolve dalla scrittura di JavaScript efficiente! :-)


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.