Pregunta Prácticas recomendadas comúnmente aceptadas en torno a la organización del código en JavaScript [cerrado]


Como los frameworks de JavaScript como jQuery hacen que las aplicaciones web del lado del cliente sean más ricas y más funcionales, comencé a notar un problema ...

¿Cómo diablos mantienes esto organizado?

  • Pon todos tus controladores en un solo lugar y escribe funciones para todos los eventos.
  • Crear funciones / clases para envolver toda su funcionalidad?
  • Escribir como loco y solo espero que funcione para mejor?
  • ¿Renunciar y obtener una nueva carrera?

Menciono jQuery, pero en realidad es cualquier código JavaScript en general. Me doy cuenta de que a medida que las líneas y líneas comienzan a acumularse, es más difícil administrar los archivos de script o encontrar lo que estás buscando. Posiblemente los problemas más grandes que he encontrado es que hay tantas maneras de hacer lo mismo, es difícil saber cuál es la mejor práctica comúnmente aceptada en la actualidad.

¿Hay alguna recomendación general sobre la mejor manera de mantener su .js archivos tan agradables y aseados como el resto de tu aplicación? ¿O es solo una cuestión de IDE? ¿Hay una mejor opción por ahí?


EDITAR

Esta pregunta tenía como objetivo ser más acerca de la organización del código y no de la organización del archivo. Ha habido algunos buenos ejemplos de fusión de archivos o división de contenido.

Mi pregunta es: ¿cuál es la forma de mejores prácticas comúnmente aceptada actualmente para organizar su código real? ¿Cuál es tu manera, o incluso una forma recomendada de interactuar con elementos de página y crear código reutilizable que no entre en conflicto?

Algunas personas han enumerado espacios de nombres que es una buena idea ¿Cuáles son algunas otras formas, más específicamente tratar con elementos en la página y mantener el código organizado y ordenado?


537
2017-10-29 15:19


origen


Respuestas:


Sería mucho más agradable si Javascript tuviera espacios de nombres integrados, pero encuentro que organizar cosas como Dustin Diaz describe aquí me ayuda mucho

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

Puse diferentes "espacios de nombres" y, a veces, clases individuales en archivos separados. Por lo general, empiezo con un archivo y, a medida que una clase o espacio de nombres crece lo suficiente como para garantizarlo, lo separo en su propio archivo. Usar una herramienta para combinar todos tus archivos para producción también es una excelente idea.


170



Intento evitar incluir cualquier javascript con el HTML. Todo el código está encapsulado en clases y cada clase está en su propio archivo. Para el desarrollo, tengo etiquetas <script> separadas para incluir cada archivo js, ​​pero se fusionan en un solo paquete más grande para producción para reducir la sobrecarga de las solicitudes HTTP.

Normalmente, tendré un único archivo 'principal' js para cada aplicación. Entonces, si estuviera escribiendo una aplicación de "encuesta", tendría un archivo js llamado "survey.js". Esto contendría el punto de entrada en el código jQuery. Creo referencias de jQuery durante la creación de instancias y luego las paso a mis objetos como parámetros. Esto significa que las clases de JavaScript son 'puras' y no contienen ninguna referencia a identificadores de CSS o nombres de clases.

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

También encuentro que nombrar las convenciones es importante para la legibilidad. Por ejemplo: antepongo 'j' a todas las instancias de jQuery.

En el ejemplo anterior, hay una clase llamada DimScreen. (Supongamos que atenúa la pantalla y aparece un cuadro de alerta.) Necesita un elemento div que se pueda agrandar para cubrir la pantalla, y luego agregue un cuadro de alerta, así que paso un objeto jQuery. jQuery tiene un concepto de complemento, pero parecía limitado (por ejemplo, las instancias no son persistentes y no se puede acceder) sin una ventaja real. Entonces la clase DimScreen sería una clase javascript estándar que simplemente usa 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>');
  //...
};

Construí algunas aplicaciones bastante complejas usando este enfoque.


83



Puede dividir sus scripts en archivos separados para su desarrollo, luego, cree una versión de "lanzamiento" donde los meta todos juntos y los ejecute Compresor YUI o algo similar en eso.


37



Inspirado por publicaciones anteriores hice una copia de Rakefile y vendedor directorios distribuidos con WysiHat (una RTE mencionada por changelog) e hizo algunas modificaciones para incluir la verificación de código con JSLint y minificación con Compresor YUI.

La idea es usar Piñones (desde WysiHat) para fusionar múltiples JavaScripts en un solo archivo, verificar la sintaxis del archivo fusionado con JSLint y minificarlo con YUI Compressor antes de la distribución.

Requisitos previos

  • Java Runtime
  • gema de rubí y rastrillo
  • Debes saber cómo poner un JAR en Classpath

Ahora haz

  1. Descargar Rinoceronte y pon el JAR ("js.jar") en tu classpath
  2. Descargar Compresor YUI y pon el JAR (build / yuicompressor-xyz.jar) en tu classpath
  3. Descargar WysiHat y copia el directorio "proveedor" a la raíz de tu proyecto de JavaScript
  4. Descargar JSLint para Rhino y ponerlo dentro del directorio "proveedor"

Ahora crea un archivo llamado "Rakefile" en el directorio raíz del proyecto JavaScript y agregale el siguiente contenido:

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 hiciste todo correctamente, deberías poder usar los siguientes comandos en tu consola:

  • rake merge - fusionar diferentes archivos JavaScript en uno
  • rake check - para verificar la sintaxis de su código (este es el defecto tarea, por lo que puede simplemente escribir rake)
  • rake minify - para preparar una versión reducida de tu código JS

En la fusión de fuentes

Usando Sprockets, el preprocesador de JavaScript puede incluir (o require) otros archivos de JavaScript. Use la siguiente sintaxis para incluir otras secuencias de comandos desde el archivo inicial (llamado "main.js", pero puede cambiar eso en el 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
})();

Y entonces...

Eche un vistazo a Rakefile provisto con WysiHat para configurar las pruebas automatizadas de la unidad. Lindas cosas :)

Y ahora la respuesta

Esto no responde muy bien a la pregunta original. Lo sé y lo siento, pero lo publiqué aquí porque espero que pueda ser útil para otra persona organizar su desorden.

Mi enfoque del problema es hacer todo el modelado orientado a objetos que pueda y separar implementaciones en diferentes archivos. Entonces los manejadores deben ser lo más cortos posible. El ejemplo con ListSingleton también es bueno.

Y espacios de nombres ... bueno, pueden ser imitados por una estructura de objetos más profunda.

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

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

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

No soy muy fanático de las imitaciones, pero esto puede ser útil si tiene muchos objetos que le gustaría mover fuera del alcance global.


26



La organización del código requiere la adopción de convenciones y estándares de documentación:
1. Código de espacio de nombres para un archivo físico;

Exc = {};


2. Clases grupales en estos espacios de nombres javascript;
3. Establecer Prototipos o funciones relacionadas o clases para representar objetos del mundo real;


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


4. Establezca convenciones para mejorar el código. Por ejemplo, agrupe todas sus funciones internas o métodos en su atributo de clase de un tipo de objeto.

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


5. Haga documentación de espacios de nombres, clases, métodos y variables. Cuando sea necesario, también discuta parte del código (algunas IF y Fors, generalmente implementan una lógica importante del código).

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


Estos son solo algunos consejos, pero eso ha ayudado enormemente a organizar el código. Recuerde que debe tener disciplina para tener éxito.


18



Seguir los principios de diseño de OO y los patrones de diseño es muy útil para hacer que su código sea fácil de mantener y comprender. Pero una de las mejores cosas que he descubierto recientemente son las señales y las ranuras, también conocido como publicar / suscribir. Mira esto http://markdotmeyer.blogspot.com/2008/09/jquery-publish-subscribe.html para una implementación simple de jQuery.

La idea se usa bien en otros idiomas para el desarrollo de GUI. Cuando sucede algo significativo en algún lugar de su código, publica un evento sintético global al que otros métodos en otros objetos pueden suscribirse. Esto proporciona una excelente separación de objetos.

Creo que Dojo (¿y Prototype?) Tienen una versión integrada de esta técnica.

ver también ¿Qué son señales y ranuras?


13



Pude aplicar con éxito Patrón de módulo de Javascript a una aplicación Ext JS en mi trabajo anterior. Proporcionó una forma simple de crear código encapsulado.


12