Meilleures pratiques communément acceptées concernant l'organisation du code en JavaScript [fermé]

561

Comme les frameworks JavaScript comme jQuery rendent les applications Web côté client plus riches et plus fonctionnelles, j'ai commencé à remarquer un problème ...

Comment diable gardez-vous cela organisé?

  • Mettez tous vos gestionnaires au même endroit et écrivez des fonctions pour tous les événements?
  • Créer des fonctions / classes pour envelopper toutes vos fonctionnalités?
  • Écrivez comme un fou et espérez juste que ça marche pour le mieux?
  • Abandonner et entreprendre une nouvelle carrière?

Je mentionne jQuery, mais c'est vraiment n'importe quel code JavaScript en général. Je constate que lorsque les lignes sur les lignes commencent à s'accumuler, il devient plus difficile de gérer les fichiers de script ou de trouver ce que vous recherchez. Il est possible que le plus gros problème que j'ai trouvé est qu'il existe de nombreuses façons de faire la même chose, il est difficile de savoir laquelle est la meilleure pratique actuellement acceptée.

Existe-t-il des recommandations générales sur la meilleure façon de conserver vos fichiers .js aussi agréables et soignés que le reste de votre application? Ou est-ce juste une question d'IDE? Y a-t-il une meilleure option là-bas?


ÉDITER

Cette question visait davantage l'organisation du code et non l'organisation des fichiers. Il y a eu de très bons exemples de fusion de fichiers ou de partage de contenu.

Ma question est: quelle est la meilleure méthode actuellement acceptée pour organiser votre code actuel? Quelle est votre façon, ou même une manière recommandée d'interagir avec les éléments de la page et de créer du code réutilisable qui n'entre pas en conflit les uns avec les autres?

Certaines personnes ont répertorié les espaces de noms, ce qui est une bonne idée. Quelles sont les autres façons de traiter plus spécifiquement les éléments de la page et de garder le code organisé et soigné?

Hugoware
la source
quelqu'un qui a réellement pris le temps de parler de l'organisation du code lui-même, et non "seulement" de l'outil qu'il utilise pour concaténer et compresser ses fichiers JS: stackoverflow.com/questions/16736483/…
Adrien Be

Réponses:

183

Ce serait beaucoup plus agréable si javascript avait des espaces de noms intégrés, mais je trouve que l'organisation de choses comme Dustin Diaz décrit ici m'aide beaucoup.

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
            }
    };
})();

J'ai mis différents "espaces de noms" et parfois des classes individuelles dans des fichiers séparés. Habituellement, je commence avec un fichier et comme une classe ou un espace de noms devient suffisamment grand pour le justifier, je le sépare dans son propre fichier. L'utilisation d'un outil pour combiner tous vos fichiers pour la production est également une excellente idée.

polarbear
la source
24
J'appelle généralement cela "la voie crockford". +1 de moi
Matt Briggs
4
Vous pouvez même aller un peu plus loin. Voir ce lien: wait-till-i.com/2007/08/22/…
MKroehnert
4
@MattBriggs autrement appelé le module patternet il est basé sur le IIFE pattern.
Adrien Be
N'avez-vous pas besoin d'exporter des classes d'une manière ou d'une autre? Comment un objet est-il créé de l'extérieur d'un tel module? Ou devrait-il y avoir une méthode createNewSomething()dans l'objet de retour, afin que la création d'objet se fasse uniquement dans le module? Hm ... Je m'attendrais à ce que les classes (constructeurs) soient visibles de l'extérieur.
robsch
@robsch Son exemple ne prend aucun paramètre, mais la plupart le feraient. Voir mon exemple ici pour savoir comment cela se fait habituellement (TypeScript, mais 99% identique): repl.it/@fatso83/Module-Pattern-in-TypeScript
oligofren
88

J'essaie d'éviter d'inclure tout javascript avec le HTML. Tout le code est encapsulé dans des classes et chaque classe est dans son propre fichier. Pour le développement, j'ai des balises <script> distinctes pour inclure chaque fichier js, mais elles sont fusionnées dans un seul package plus grand pour la production afin de réduire la surcharge des requêtes HTTP.

En règle générale, j'ai un seul fichier js «principal» pour chaque application. Donc, si j'écrivais une application "survey", j'aurais un fichier js appelé "survey.js". Cela contiendrait le point d'entrée dans le code jQuery. Je crée des références jQuery lors de l'instanciation puis les passe dans mes objets en tant que paramètres. Cela signifie que les classes javascript sont «pures» et ne contiennent aucune référence aux identifiants CSS ou aux noms de classe.

// 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();
});

Je trouve également que la convention de dénomination est importante pour la lisibilité. Par exemple: je ajoute «j» à toutes les instances de jQuery.

Dans l'exemple ci-dessus, il existe une classe appelée DimScreen. (Supposons que cela assombrit l'écran et affiche une boîte d'alerte.) Il a besoin d'un élément div qu'il peut agrandir pour couvrir l'écran, puis ajouter une boîte d'alerte, donc je passe un objet jQuery. jQuery a un concept de plug-in, mais il semblait limité (par exemple, les instances ne sont pas persistantes et ne sont pas accessibles) sans réel avantage. Ainsi, la classe DimScreen serait une classe javascript standard qui se trouve simplement utiliser 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>');
  //...
};

J'ai construit des applications assez complexes en utilisant cette approche.

Jason Moore
la source
15
Je trouve que l'utilisation $comme préfixe de nom de variable est une pratique plus courante, mais je peux me tromper. Donc, $s = $('...')au lieu de jS = $('...'), juste une question de préférence, je suppose. Intéressant cependant, car la notation hongroise est considérée comme une odeur de code. C'est bizarre à quel point certaines de mes conventions / préférences de code JavaScript sont différentes de mes conventions de codage C # / Java.
jamiebarrow
9
@jamie Ce n'est pas une odeur de code dans ce cas, c'est précisément l'un des rares cas où le hongrois est bon . Vous voudrez peut-être lire ceci .
Dan Abramov
3
@DanAbramov merci pour le lien. Je dois vraiment lire tous les blogs de Joel, il explique si bien les choses. Mérite certainement la renommée / réputation qu'il a. Je ferai référence à Systems Hungarianune odeur de code et Apps Hungarianà une pratique à partir de maintenant :)
jamiebarrow
Je suppose que dans le monde C #, cela pourrait aussi être un excellent article pour promouvoir l'utilisation de var, maintenant que j'y pense. La plupart des arguments contre l'utilisation varsont ceux où vous ne serez pas sûr du «type» de ce qui est retourné, mais je suppose que l'argument devrait plutôt être contre ne pas connaître la «classe» de ce qui est retourné. Si vous utilisez des applications hongroises, vous ne devriez pas avoir ce souci alors ... intéressant.
jamiebarrow
3
@Marnen: Je vois votre point, mais il n'est pas inutile comme guide pour le programmeur. Le préfixe $ me rappelle ce que c'est quand je lis mon code plus tard, et aide ainsi à une compréhension plus rapide.
Sean
39

Vous pouvez diviser vos scripts en fichiers séparés pour le développement, puis créer une version "release" où vous les regroupez tous et exécutez YUI Compressor ou quelque chose de similaire.

Greg
la source
Parfois, il existe des scripts javascript inutiles. C'est inutile de les envoyer au client. Je pense qu'il ne faut envoyer que ce dont on a besoin. Bien sûr, pour une application Web utilisée toute la journée, telle qu'une application intranet, il pourrait être préférable d'envoyer le lot entier à la fois, lors du premier chargement de la page.
DOK
2
La compilation @DOK devrait inclure l'excision des éléments inutilisés.
aehlke
Il existe également un concept de chargement paresseux pour essayer de réduire les besoins en bande passante, où vous chargez la page initiale, puis effectuez un chargement asynchrone des fichiers de script requis (comme mentionné dans d'autres réponses à cette question). Cependant, cela peut nécessiter plus de demandes et pourrait en fait être moins utilisable. @DOK, si le JS est mis en cache, une demande moyenne peut être meilleure que quelques petites.
jamiebarrow
27

Inspiré par les articles précédents, j'ai fait une copie de Rakefile et des répertoires des fournisseurs distribués avec WysiHat (un RTE mentionné par le changelog) et j'ai apporté quelques modifications pour inclure la vérification de code avec JSLint et la minification avec YUI Compressor .

L'idée est d'utiliser Sprockets (de WysiHat) pour fusionner plusieurs JavaScripts en un seul fichier, vérifier la syntaxe du fichier fusionné avec JSLint et le minimiser avec YUI Compressor avant la distribution.

Conditions préalables

  • Java Runtime
  • rubis et râteau gemme
  • Vous devez savoir comment mettre un JAR dans Classpath

Maintenant

  1. Téléchargez Rhino et placez le JAR ("js.jar") dans votre chemin de classe
  2. Téléchargez YUI Compressor et placez le JAR (build / yuicompressor-xyz.jar) dans votre chemin de classe
  3. Téléchargez WysiHat et copiez le répertoire "vendeur" à la racine de votre projet JavaScript
  4. Téléchargez JSLint pour Rhino et placez-le dans le répertoire "vendeur"

Créez maintenant un fichier nommé "Rakefile" dans le répertoire racine du projet JavaScript et ajoutez-y le contenu suivant:

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

Si vous avez tout fait correctement, vous devriez pouvoir utiliser les commandes suivantes dans votre console:

  • rake merge - pour fusionner différents fichiers JavaScript en un seul
  • rake check- pour vérifier la syntaxe de votre code (c'est la tâche par défaut , vous pouvez donc simplement taper rake)
  • rake minify - pour préparer une version minifiée de votre code JS

Fusion à la source

À l'aide de Sprockets, le pré-processeur JavaScript, vous pouvez inclure (ou require) d'autres fichiers JavaScript. Utilisez la syntaxe suivante pour inclure d'autres scripts du fichier initial (nommé "main.js", mais vous pouvez changer cela dans le 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
})();

Et alors...

Jetez un œil à Rakefile fourni avec WysiHat pour configurer les tests unitaires automatisés. Jolies choses :)

Et maintenant pour la réponse

Cela ne répond pas très bien à la question d'origine. Je le sais et je suis désolé, mais je l'ai posté ici parce que j'espère que cela pourrait être utile à quelqu'un d'autre pour organiser son désordre.

Mon approche du problème consiste à faire autant de modélisation orientée objet que possible et à séparer les implémentations dans différents fichiers. Ensuite, les gestionnaires doivent être aussi courts que possible. L'exemple avec Listsingleton est également sympa.

Et les espaces de noms ... eh bien ils peuvent être imités par une structure d'objet plus profonde.

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

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

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

Je ne suis pas un grand fan d'imitations, mais cela peut être utile si vous avez de nombreux objets que vous souhaitez déplacer hors de la portée mondiale.

Damir Zekić
la source
18

L'organisation du code nécessite l'adoption de conventions et de normes de documentation:
1. Code d'espace de noms pour un fichier physique;

Exc = {};


2. Grouper les classes dans ces espaces de noms javascript;
3. Définir des prototypes ou des fonctions ou classes connexes pour représenter des objets du monde réel;

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


4. Définissez des conventions pour améliorer le code. Par exemple, regroupez toutes ses fonctions ou méthodes internes dans son attribut de classe d'un type d'objet.

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


5. Faites la documentation des espaces de noms, des classes, des méthodes et des variables. Le cas échéant, discutez également d'une partie du code (certains FI et Fors, ils implémentent généralement une logique importante du code).

/**
  * 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;
    ...
};


Ce ne sont que quelques conseils, mais cela a grandement aidé à organiser le code. N'oubliez pas que vous devez avoir de la discipline pour réussir!

Nery Jr
la source
13

Suivre de bons principes et modèles de conception OO contribue grandement à rendre votre code facile à maintenir et à comprendre. Mais l'une des meilleures choses que j'ai découvertes récemment sont les signaux et les machines à sous, c'est-à-dire publier / s'abonner. Jetez un œil à http://markdotmeyer.blogspot.com/2008/09/jquery-publish-subscribe.html pour une implémentation jQuery simple.

L'idée est bien utilisée dans d'autres langues pour le développement de GUI. Lorsque quelque chose d'important se produit quelque part dans votre code, vous publiez un événement synthétique global auquel d'autres méthodes dans d'autres objets peuvent souscrire. Cela donne une excellente séparation des objets.

Je pense que Dojo (et Prototype?) Ont une version intégrée de cette technique.

voir aussi Que sont les signaux et les slots?

meouw
la source
Je l'ai fait dans jQuery. JS a un modèle d'événement intégré, vous n'avez donc pas vraiment besoin de beaucoup de support de framework.
Marnen Laibow-Koser
12

J'ai pu appliquer avec succès le modèle de module Javascript à une application Ext JS lors de mon travail précédent. Il a fourni un moyen simple de créer du code bien encapsulé.

Alan
la source
11

Dojo avait le système de modules depuis le premier jour. En fait, il est considéré comme une pierre angulaire du Dojo, la colle qui tient tout cela ensemble:

L'utilisation des modules Dojo atteint les objectifs suivants:

  • Espaces de noms pour le code Dojo et le code personnalisé ( dojo.declare()) - ne polluent pas l'espace global, ne coexistent pas avec d'autres bibliothèques et le code non compatible Dojo de l'utilisateur.
  • Chargement des modules de manière synchrone ou asynchrone par nom ( dojo.require()).
  • Constructions personnalisées en analysant les dépendances des modules pour créer un seul fichier ou un groupe de fichiers interdépendants (appelés couches) pour inclure uniquement les besoins de votre application Web. Les constructions personnalisées peuvent également inclure des modules Dojo et des modules fournis par le client.
  • Accès transparent basé sur CDN au Dojo et au code utilisateur. AOL et Google proposent Dojo de cette façon, mais certains clients le font également pour leurs applications Web personnalisées.
Eugene Lazutkin
la source
9

Découvrez JavasciptMVC .

Vous pouvez :

  • divisez votre code en couches de modèle, de vue et de contrôleur.

  • compresser tout le code dans un seul fichier de production

  • code auto-généré

  • créer et exécuter des tests unitaires

  • et beaucoup plus...

Mieux encore, il utilise jQuery, vous pouvez donc également profiter d'autres plugins jQuery.

andyuk
la source
Ouais, j'ai utilisé jmvc et c'est assez bon - les documents pourraient être mieux
meouw
9

Mon patron parle toujours de l'époque où ils ont écrit du code modulaire (langage C), et se plaint de la merde du code de nos jours! On dit que les programmeurs peuvent écrire des assemblys dans n'importe quel framework. Il existe toujours une stratégie pour surmonter l'organisation du code. Le problème de base est avec les gars qui traitent le script java comme un jouet et n'essaient jamais de l'apprendre.

Dans mon cas, j'écris des fichiers js sur un thème d'interface utilisateur ou sur un écran d'application, avec un init_screen () approprié. En utilisant la convention de dénomination id appropriée, je m'assure qu'il n'y a pas de conflits d'espace de nom au niveau de l'élément racine. Dans le window.load () discret, j'attache les choses en fonction de l'ID de niveau supérieur.

J'utilise strictement les fermetures et les modèles de scripts Java pour masquer toutes les méthodes privées. Après cela, je n'ai jamais été confronté à un problème de propriétés / définitions de fonction / définitions de variables conflictuelles. Cependant, lorsque vous travaillez avec une équipe, il est souvent difficile d'appliquer la même rigueur.

questzen
la source
9

Je suis surpris que personne n'ait mentionné les frameworks MVC. J'ai utilisé Backbone.js pour modulariser et découpler mon code, et cela a été inestimable.

Il existe un certain nombre de ces types de cadres, et la plupart d'entre eux sont également minuscules. Mon opinion personnelle est que si vous allez écrire plus que quelques lignes de jQuery pour des choses d'interface utilisateur flashy, ou si vous voulez une application Ajax riche, un framework MVC vous facilitera la vie.

Chétan
la source
8

"Ecrire comme un fou et espérer que ça marche pour le mieux?", J'ai vu un projet comme celui-ci qui a été développé et maintenu par seulement 2 développeurs, une énorme application avec beaucoup de code javascript. En plus de cela, il y avait différents raccourcis pour chaque fonction jquery possible à laquelle vous pouvez penser. J'ai suggéré qu'ils organisent le code en plugins, car c'est l'équivalent jquery de la classe, du module, de l'espace de noms ... et de l'univers entier. Mais les choses ont empiré, maintenant ils ont commencé à écrire des plugins remplaçant chaque combinaison de 3 lignes de code utilisées dans le projet. Personnellement, je pense que jQuery est le diable et qu'il ne devrait pas être utilisé sur des projets avec beaucoup de javascript car il vous encourage à être paresseux et à ne pas penser à organiser le code en aucune façon. Je préfère lire 100 lignes de javascript plutôt qu'une ligne avec 40 fonctions jQuery chaînées (je ' je ne plaisante pas). Contrairement à la croyance populaire, il est très facile d'organiser le code javascript en équivalents aux espaces de noms et aux classes. C'est ce que font YUI et Dojo. Vous pouvez facilement rouler le vôtre si vous le souhaitez. Je trouve l'approche de YUI bien meilleure et efficace. Mais vous avez généralement besoin d'un bel éditeur avec prise en charge des extraits pour compenser les conventions de dénomination YUI si vous souhaitez écrire quelque chose d'utile.

Vasil
la source
3
Je suis d'accord avec vous sur les commandes enchaînées vraiment longues, mais l'une des meilleures parties de jQuery est qu'il garde tout Javascript hors HTML. Vous pouvez configurer des gestionnaires d'événements pour tous vos éléments sans "avoir besoin" d'ajouter des ID ou sur des événements <what> sur vos éléments. Comme toujours, la
surutilisation
J'ai travaillé sur d'énormes projets bien organisés dans jQuery. Je ne sais pas pourquoi vous pensez que cela gêne l'organisation.
Marnen Laibow-Koser
7

Je crée des singletons pour tout ce que je n'ai vraiment pas besoin d'instancier plusieurs fois à l'écran, des cours pour tout le reste. Et tous sont placés dans le même espace de noms dans le même fichier. Tout est commenté et conçu avec des diagrammes d'état UML. Le code javascript est clair de html donc pas de javascript en ligne et j'ai tendance à utiliser jquery pour minimiser les problèmes entre navigateurs.

Nikola Stjelja
la source
3
bon commentaire est CLÉ - je suis content que vous l'ayez dit donc je n'ai pas eu à le faire. J'ajouterais des conventions de dénomination cohérentes, une sorte de stratégie d'organisation facilement compréhensible pour les variables & amp; fonctions, et comme vous l'avez mentionné, l'utilisation judicieuse des classes par rapport aux singletons.
matt lohkamp
Non. Si vous avez besoin de commentaires, votre code n'est généralement pas suffisamment lisible. Efforcez-vous d'écrire du code qui n'a pas besoin de commentaires.
Marnen Laibow-Koser
De plus, si vous avez besoin d'UML et de diagrammes d'état, cela signifie probablement que votre architecture n'est pas suffisamment claire du code. Downvoting.
Marnen Laibow-Koser
1
@Marnen Des projets bien écrits incluent des commentaires pour décrire POURQUOI, pas nécessairement QUOI. Le code décrit déjà le QUOI, mais souvent vous avez besoin de quelque chose pour décrire POURQUOI. Upvoting.
Cypher
@Cypher Les projets bien écrits ont un code suffisamment clair pour que vous puissiez généralement dire le "pourquoi", pas seulement le "quoi". Je ne ferais pas confiance à un commentaire pour me dire le "pourquoi", car je n'ai aucune garantie qu'il soit en phase avec le code. Laissez le document de code lui-même.
Marnen Laibow-Koser
6

Dans mon dernier projet -Viajeros.com-, j'ai utilisé une combinaison de plusieurs techniques. Je ne saurais pas comment organiser une application Web - Viajeros est un site de réseautage social pour les voyageurs avec des sections bien définies, il est donc assez facile de séparer le code pour chaque zone.

J'utilise la simulation d'espace de noms et le chargement paresseux des modules selon la section du site. Sur chaque chargement de page, je déclare un objet "vjr" et lui charge toujours un ensemble de fonctions communes (vjr.base.js). Ensuite, chaque page HTML décide quels modules ont besoin avec un simple:

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

Vjr.base.js obtient chacun gzippé du serveur et les exécute.

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"
      });
    }
  }
};

Chaque "module" a cette structure:

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);

Compte tenu de ma connaissance limitée de Javascript, je sais qu'il doit y avoir de meilleures façons de gérer cela, mais jusqu'à présent, cela fonctionne très bien pour nous.

Danita
la source
6

L'organisation de votre code d'une manière NameSpace centrée sur Jquery peut ressembler à ceci ... et ne sera pas en conflit avec d'autres API Javascript comme Prototype, Ext non plus.

<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>

J'espère que cela t'aides.

Darryl
la source
Cela me semble être un petit cargo. jQuery.fnest un pointeur vers jQuery.prototype, car $()renvoie en fait une nouvelle instance de la fonction constructeur jQuery. Ajouter un «plugin» à jQuery signifie simplement étendre son prototype. Mais ce que vous faites n'est pas cela, et il existe des moyens plus propres d'accomplir la même chose.
Adam Lassek
Je crois qu'il crée simplement des fonctions statiques. Je me souviens avoir vu dans les documents de jQuery que cette façon de déclarer des fonctions statiques était acceptable
Alex Heyd
6

Un bon principe de OO + MVC contribuerait certainement à la gestion d'une application javascript complexe.

Fondamentalement, j'organise mon application et javascript selon la conception familière suivante (qui existe depuis mes jours de programmation de bureau jusqu'au Web 2.0)

JS OO et MVC

Description des valeurs numériques sur l'image:

  1. Widgets représentant les vues de mon application. Cela devrait être extensible et séparé, ce qui entraînerait une bonne séparation que MVC essaie de réaliser plutôt que de transformer mon widget en un code spaghetti (équivalent dans l'application Web de mettre un grand bloc de Javascript directement en HTML). Chaque widget communique via d'autres en écoutant l'événement généré par d'autres widgets réduisant ainsi le fort couplage entre les widgets qui pourrait conduire à un code ingérable (rappelez-vous le jour de l'ajout d'un onclick partout pointant vers une fonction globale dans la balise de script? Urgh ...)
  2. Modèles d'objet représentant les données que je souhaite remplir dans les widgets et transmettant au serveur. En encapsulant les données dans son modèle, l'application devient indépendante du format des données. Par exemple: bien que naturellement en Javascript ces modèles d'objets soient principalement sérialisés et désérialisés en JSON, si le serveur utilise XML pour la communication, tout ce que je dois changer est de changer la couche de sérialisation / désérialisation et pas nécessairement de changer toutes les classes de widget .
  3. Classes de contrôleur qui gèrent la logique métier et la communication avec le serveur + parfois la couche de mise en cache. Cette couche contrôle le protocole de communication avec le serveur et place les données nécessaires dans les modèles d'objets
  4. Les classes sont bien emballées dans leurs espaces de noms correspondants. Je suis sûr que nous savons tous à quel point l'espace de noms global pourrait être désagréable en Javascript.

Dans le passé, je séparais les fichiers en ses propres js et j'utilisais une pratique courante pour créer des principes OO en Javascript. Le problème que j'ai vite constaté, c'est qu'il y a plusieurs façons d'écrire JS OO et ce n'est pas forcément que tous les membres de l'équipe ont la même approche. Au fur et à mesure que l'équipe s'est agrandie (dans mon cas, plus de 15 personnes), cela se complique car il n'y a pas d'approche standard pour Javascript orienté objet. En même temps, je ne veux pas écrire mon propre cadre et répéter une partie du travail que je suis sûr que les gens sont plus intelligents que j'ai résolu.

jQuery est incroyablement agréable en tant que framework Javascript et je l'adore, mais à mesure que le projet s'agrandit, j'ai clairement besoin d'une structure supplémentaire pour mon application Web, en particulier pour faciliter la normalisation de la pratique OO. Pour moi, après plusieurs expériences, je trouve que l'infrastructure YUI3 Base and Widget ( http://yuilibrary.com/yui/docs/widget/ et http://yuilibrary.com/yui/docs/base/index.html ) fournit exactement ce dont j'ai besoin. Peu de raisons pour lesquelles je les utilise.

  1. Il fournit un support d'espace de noms. Un réel besoin d'OO et une organisation soignée de votre code
  2. Il prend en charge la notion de classes et d'objets
  3. Il donne un moyen standardisé d'ajouter des variables d'instance à votre classe
  4. Il prend parfaitement en charge l'extension de classe
  5. Il fournit constructeur et destructeur
  6. Il fournit un rendu et une liaison d'événements
  7. Il a un cadre de widget de base
  8. Chaque widget peut désormais communiquer entre eux à l'aide d'un modèle standard basé sur des événements
  9. Plus important encore, cela donne à tous les ingénieurs une norme OO pour le développement Javascript

Contrairement à de nombreuses vues, je n'ai pas forcément à choisir entre jQuery et YUI3. Ces deux peuvent coexister pacifiquement. Alors que YUI3 fournit le modèle OO nécessaire pour mon application Web complexe, jQuery fournit toujours à mon équipe une abstraction JS facile à utiliser que nous aimons tous et que nous connaissons tous.

À l'aide de YUI3, j'ai réussi à créer un modèle MVC en séparant les classes qui étendent la base en tant que modèle, les classes qui étendent le widget en tant que vue et, bien sûr, vous avez des classes Controller qui effectuent les appels logiques et côté serveur nécessaires.

Le widget peut communiquer entre eux en utilisant un modèle basé sur les événements et en écoutant l'événement et en effectuant la tâche nécessaire en fonction d'une interface prédéfinie. En termes simples, mettre la structure OO + MVC sur JS est une joie pour moi.

Juste un avertissement, je ne travaille pas pour Yahoo! et simplement un architecte qui essaie de faire face au même problème que celui posé par la question d'origine. Je pense que si quelqu'un trouve un cadre OO équivalent, cela fonctionnerait aussi. Principalement, cette question s'applique également à d'autres technologies. Merci à Dieu pour toutes les personnes qui ont conçu OO Principles + MVC pour rendre nos journées de programmation plus faciles à gérer.

momo
la source
5

J'utilise la gestion des packages ( dojo.requireet dojo.provide) et le système de classes de Dojo ( dojo.declarequi permet également un héritage multiple simple) pour modulariser toutes mes classes / widgets dans des fichiers séparés. Non seulement cela permet de garder votre code organisé, mais cela vous permet également de charger paresseusement / juste à temps des classes / widgets.

Justin Johnson
la source
3

Il y a quelques jours, les gars de 37Signals ont sorti un contrôle RTE , avec une torsion. Ils ont créé une bibliothèque qui regroupe les fichiers javascript à l'aide d'une sorte de commandes de pré-processeur.

Je l'utilise depuis pour séparer mes fichiers JS et finalement les fusionner en un seul. De cette façon, je peux séparer les préoccupations et, à la fin, avoir un seul fichier qui passe par le canal (gzippé, pas moins).

Dans vos modèles, vérifiez si vous êtes en mode développement, et incluez les fichiers séparés, et si en production, incluez le dernier (que vous devrez "construire" vous-même).

changelog
la source
1
getsprockets.org est le lien direct
Matt Gardner
3

Créez de fausses classes et assurez-vous que tout ce qui peut être jeté dans une fonction distincte qui a du sens est fait. Assurez-vous également de commenter beaucoup, et de ne pas écrire de code spagghetti, plutôt de tout garder dans les sections. Par exemple, un code absurde décrivant mes idéaux. Évidemment, dans la vie réelle, j'écris également de nombreuses bibliothèques qui englobent essentiellement leurs fonctionnalités.

$(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.
    }
};
Dmitri Farkov
la source
3

Utilisez des modèles d'héritage pour organiser de grandes applications jQuery.

Chétan
la source
Je commence à l'utiliser, même pour des choses très petites / basiques, et cela aide vraiment à garder le code propre et flexible. Cela vaut la peine d'être utilisé même pour de simples manipulations JS côté client.
Chetan
C'est ce que j'aime et j'utilise dans mes applications.
Andreas
2

Je pense que cela est lié, peut-être, au DDD (Domain-Driven Design). L'application sur laquelle je travaille, bien qu'elle ne dispose pas d'une API formelle, donne des indices à ce sujet par le biais du code côté serveur (noms de classe / fichier, etc.). Armé de cela, j'ai créé un objet de niveau supérieur en tant que conteneur pour l'ensemble du domaine problématique; puis, j'ai ajouté des espaces de noms là où c'était nécessaire:

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');
ken
la source
2

Pour l'organisation JavaScript, utilisez les éléments suivants

  1. Dossier pour tous vos javascript
  2. Le javascript au niveau de la page obtient son propre fichier portant le même nom que la page. ProductDetail.aspx serait ProductDetail.js
  3. Dans le dossier javascript pour les fichiers de bibliothèque, j'ai un dossier lib
  4. Placez les fonctions de bibliothèque associées dans un dossier lib que vous souhaitez utiliser dans votre application.
  5. Ajax est le seul javascript que je déplace en dehors du dossier javascript et obtient son propre dossier. Ensuite, j'ajoute deux sous-dossiers client et serveur
  6. Le dossier client obtient tous les fichiers .js tandis que le dossier serveur obtient tous les fichiers côté serveur.
Jason Too Cool Webs
la source
Agréable pour l'organisation des fichiers. Je fais ça avec du code. Mais à la fin, je compile mon code dans un ... disons dll. Vous en avez également besoin avec javascript ou vous finirez par demander 15 fichiers js par page.
graffic
Il n'y a rien de mal à demander 15 fichiers JS par page. De toute façon, votre navigateur les mettra en cache pour les demandes ultérieures.
Marnen Laibow-Koser
@ MarnenLaibow-Koser Le seul problème avec la demande de 15 fichiers JS sur une page est le nombre de requêtes HTTP que le navigateur peut gérer à la fois. Ainsi, les regrouper dans un seul fichier permet au navigateur de demander d'autres fichiers nécessaires en même temps.
iwasrobbed
C'est vrai, mais après les deux premiers hits, ils seront dans le cache du navigateur, donc ils n'auront pas besoin de connexions HTTP.
Marnen Laibow-Koser
2

J'utilise cette petite chose. Il vous donne la directive «include» pour les modèles JS et HTML. Il élimine complètement le gâchis.

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.
        });
    }
});
gaperton
la source
2

Vous pouvez utiliser jquery mx (utilisé dans javascriptMVC) qui est un ensemble de scripts qui vous permet d'utiliser des modèles, des vues et des contrôleurs. Je l'ai utilisé dans un projet et m'a aidé à créer du javascript structuré, avec des tailles de script minimales en raison de la compression. Ceci est un exemple de contrôleur:

$.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'));

Vous pouvez également utiliser uniquement le côté contrôleur de jquerymx si vous n'êtes pas intéressé par les parties vue et modèle.

rolnn
la source
1

Votre question est celle qui m'a tourmenté à la fin de l'année dernière. La différence - remettre le code à de nouveaux développeurs qui n'avaient jamais entendu parler des méthodes privées et publiques. J'ai dû construire quelque chose de simple.

Le résultat final a été un petit framework (environ 1 Ko) qui traduit les littéraux d'objet en jQuery. La syntaxe est visuellement plus facile à analyser, et si votre js grandit vraiment, vous pouvez écrire des requêtes réutilisables pour trouver des choses comme les sélecteurs utilisés, les fichiers chargés, les fonctions dépendantes, etc.

Poster un petit framework ici n'est pas pratique, j'ai donc écrit un blog avec des exemples (Mon premier. C'était une aventure!). Vous êtes invités à jeter un œil.

Pour tous les autres ici avec quelques minutes pour le vérifier, j'apprécierais grandement les commentaires!

FireFox est recommandé car il prend en charge toSource () pour l'exemple de requête d'objet.

À votre santé!

Adam

Adam
la source
0

J'utilise un script personnalisé inspiré du comportement de Ben Nolan (je ne trouve malheureusement plus de lien actuel vers cela) pour stocker la plupart de mes gestionnaires d'événements. Ces gestionnaires d'événements sont déclenchés par les éléments className ou Id, par exemple. Exemple:

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

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

});

J'aime inclure la plupart de mes bibliothèques Javascript à la volée, sauf celles qui contiennent un comportement global. J'utilise pour cela l' aide de l'espace réservé headScript () de Zend Framework , mais vous pouvez également utiliser javascript pour charger d'autres scripts à la volée avec Ajile par exemple.

Aron Rotteveel
la source
Est ce que c'est ce que vous recherchiez? koders.com/javascript/…
DOK
Ouais, c'est celui-là! :) Il semble que le code derrière le lien soit plus récent que la version qui m'a inspiré. Merci pour votre effort!
Aron Rotteveel
0

Vous ne mentionnez pas votre langue côté serveur. Ou, plus pertinemment, quel framework vous utilisez - le cas échéant - côté serveur.

IME, j'organise les choses côté serveur et je laisse tout bouger sur la page Web. Le framework est chargé d'organiser non seulement JS que chaque page doit charger, mais aussi des fragments JS qui fonctionnent avec le balisage généré. De tels fragments que vous ne voulez généralement pas émettre plus d'une fois - c'est pourquoi ils sont extraits dans le cadre de ce code pour résoudre ce problème. :-)

Pour les pages de fin qui doivent émettre leur propre JS, je trouve généralement qu'il existe une structure logique dans le balisage généré. De tels JS localisés peuvent souvent être assemblés au début et / ou à la fin d'une telle structure.

Notez que rien de tout cela ne vous dispense d'écrire du JavaScript efficace! :-)

staticsan
la source
0

Lazy Chargez le code dont vous avez besoin sur demande. Google fait quelque chose comme ça avec leur google.loader

Brig Lamoreaux
la source