Patrón de módulo de JavaScript con ejemplo [cerrado]

136

No puedo encontrar ningún ejemplo accesible que muestre cómo dos (o más) módulos diferentes están conectados para trabajar juntos.

Entonces, me gustaría preguntar si alguien tiene tiempo para escribir un ejemplo que explique cómo los módulos funcionan juntos.

Srle
fuente
Todo esto ha cambiado en los últimos cuatro años, pero gracias a la celosa sobre-moderación, esta información desactualizada permanecerá para siempre . Aquí está la página de MDN sobre módulos ES6.
bbsimonbb

Respuestas:

256

Para acercarse al patrón de diseño modular, primero debe comprender estos conceptos:

Expresión de función invocada inmediatamente (IIFE):

(function() {
      // Your code goes here 
}());

Hay dos formas de usar las funciones. 1. Declaración de función 2. Expresión de función.

Aquí están usando la expresión de función.

¿Qué es el espacio de nombres? Ahora, si agregamos el espacio de nombres a la pieza de código anterior, entonces

var anoyn = (function() {
}());

¿Qué es el cierre en JS?

Significa que si declaramos cualquier función con cualquier alcance variable / dentro de otra función (en JS podemos declarar una función dentro de otra función), entonces contará ese alcance de función siempre. Esto significa que cualquier variable en la función externa se leerá siempre. No leerá la variable global (si hay alguna) con el mismo nombre. Este es también uno de los objetivos de utilizar un patrón de diseño modular que evite conflictos de nombres.

var scope = "I am global";
function whatismyscope() {
    var scope = "I am just a local";
    function func() {return scope;}
    return func;
}
whatismyscope()()

Ahora aplicaremos estos tres conceptos que mencioné anteriormente para definir nuestro primer patrón de diseño modular:

var modularpattern = (function() {
    // your module code goes here
    var sum = 0 ;

    return {
        add:function() {
            sum = sum + 1;
            return sum;
        },
        reset:function() {
            return sum = 0;    
        }  
    }   
}());
alert(modularpattern.add());    // alerts: 1
alert(modularpattern.add());    // alerts: 2
alert(modularpattern.reset());  // alerts: 0

jsfiddle para el código anterior.

El objetivo es ocultar la accesibilidad variable del mundo exterior.

Espero que esto ayude. Buena suerte.

kta
fuente
¿Sería mejor nombrar la vida? para fines semánticos y un mejor seguimiento de la pila? ¿Cambiaría algo en el código?
Jeroen
2
Su primer ejemplo (function() { /* Your code goes here */}());es en realidad un IIFE (expresión de función de invocación inmediata), ok es anónimo porque no tiene nombre, por lo que incluso puede llamarlo IIAFE (expresión de función anónima de invocación inmediata). Vea más sobre IIFE en stackoverflow.com/questions/ 2421911 / ...
Adrien Be
¿Por qué se ha utilizado la declaración de devolución? si omitimos return {}, ¿la función de agregar y restablecer sería pública y supongo que pueden acceder a la suma de variables locales? estoy en lo cierto?
Mou
su segundo ejemplo parece un objeto o no estoy en lo cierto?
La razón
44
Esto no responde a la pregunta del OP. Es una descripción del patrón del módulo, no un ejemplo de cómo varios módulos pueden trabajar juntos como el OP quería.
Erik Trautman
39

Realmente recomendaría a cualquiera que ingrese a este tema que lea el libro gratuito de Addy Osmani:

"Aprender patrones de diseño de JavaScript".

http://addyosmani.com/resources/essentialjsdesignpatterns/book/

Este libro me ayudó muchísimo cuando comencé a escribir JavaScript más fácil de mantener y todavía lo uso como referencia. Eche un vistazo a sus diferentes implementaciones de patrones de módulos, las explica muy bien.

Noviciado de código
fuente
También recomendaría leer mi artículo sobre el "Patrón de módulo definitivo" que no está cubierto en el libro de Addy Osmani: github.com/tfmontague/definitive-module-pattern
tfmontague
1
¿Cómo se compara esto con los "Patrones de JavaScript" por Stoyan Stefanov
JohnMerlino
44
El libro de Stoyan es mucho más completo. Cubre más que solo patrones de alto nivel, pero también habla más en profundidad sobre otras mejores prácticas de JS.
Código Noviciado
1
revisiones de "Aprendizaje de patrones de diseño de JavaScript" amazon.com/product-reviews/1449331815
Adrien Be
3
revisiones de "Patrones de JavaScript" por Stoyan Stefanov amazon.com/product-reviews/0596806752 . Nota: que parece mucho mejor que la de "Aprendizaje de patrones de diseño de JavaScript"
Adrien Be
19

Pensé que ampliaría la respuesta anterior al hablar sobre cómo encajarían los módulos en una aplicación. Había leído sobre esto en el libro de doug crockford, pero al ser nuevo en javascript, todavía era un poco misterioso.

Vengo de ac # background, así que he agregado algo de terminología que encuentro útil a partir de ahí.

HTML

Tendrá algún tipo de archivo html de nivel superior. Es útil pensar en esto como su archivo de proyecto. Cada archivo de JavaScript que agregue al proyecto quiere entrar en esto, desafortunadamente no obtiene soporte de herramientas para esto (estoy usando IDEA).

Necesita agregar archivos al proyecto con etiquetas de script como esta:

        <script type="text/javascript" src="app/native/MasterFile.js" /></script>
        <script type="text/javascript" src="app/native/SomeComponent.js" /></script>

Parece que colapsar las etiquetas hace que las cosas fallen, mientras que parece que xml es realmente algo con reglas más locas.

Archivo de espacio de nombres

MasterFile.js

myAppNamespace = {};

Eso es. Esto es solo para agregar una única variable global para que viva el resto de nuestro código. También puede declarar espacios de nombres anidados aquí (o en sus propios archivos).

Módulo (s)

SomeComponent.js

myAppNamespace.messageCounter= (function(){

    var privateState = 0;

    var incrementCount = function () {
        privateState += 1;
    };

    return function (message) {
        incrementCount();
        //TODO something with the message! 
    }
})();

Lo que estamos haciendo aquí es asignar una función de contador de mensajes a una variable en nuestra aplicación. Es una función que devuelve una función que ejecutamos inmediatamente .

Conceptos

Creo que es útil pensar en la línea superior en SomeComponent como el espacio de nombres donde está declarando algo. La única advertencia a esto es que todos sus espacios de nombres deben aparecer primero en algún otro archivo: son solo objetos enraizados por nuestra variable de aplicación.

Solo he tomado pasos menores con esto en este momento (estoy refactorizando algunos javascript normales de una aplicación extjs para poder probarlo) pero parece bastante bueno ya que puedes definir pequeñas unidades funcionales mientras evito el atolladero de 'esto ' .

También puede usar este estilo para definir constructores devolviendo una función que devuelve un objeto con una colección de funciones y no llamándolo inmediatamente.

JonnyRaa
fuente
6

Aquí https://toddmotto.com/mastering-the-module-pattern puede encontrar el patrón completamente explicado. Agregaría que la segunda cosa sobre JavaScript modular es cómo estructurar su código en múltiples archivos. Muchas personas pueden aconsejarle que vaya con AMD, pero puedo decir por experiencia que terminará en algún momento con una respuesta de página lenta debido a numerosas solicitudes HTTP. La salida es la precompilación de sus módulos JavaScript (uno por archivo) en un solo archivo siguiendo el estándar CommonJS. Echa un vistazo a las muestras aquí http://dsheiko.github.io/cjsc/

Dmitry Sheiko
fuente
Todas las implementaciones de AMD también proporcionan precompilación en un solo archivo.
I-Lin Kuo
1
Eso es correcto, pero el archivo optimizado resultante requiere la biblioteca del cargador (solo lo revisó nuevamente con r.js v2.1.14), que generalmente es bastante pesado. Tan pronto como hayamos compilado el código, no necesitamos resolver dependencias cargadas asincrónicamente, no necesitamos esta biblioteca. Solo considere: envolvemos los módulos en AMD, eso significa asíncrono. cargando, luego compílelos en un solo archivo (ya no se carga por separado), pero cargue toda la biblioteca para abordarlos (lo que es redundante ahora). No me parece una forma óptima. ¿Por qué AMD en absoluto cuando no cargamos de forma asincrónica?
Dmitry Sheiko
almond.js proporciona un cargador de peso más pequeño para el código de producción terminado que RequireJS, pero en términos comparativos, el beneficio de rendimiento de no hacer una sola solicitud http supera con creces el costo de agregar el código del cargador al módulo, por lo que si bien es menos óptimo, es a una escala mucho menor. La pregunta, en mi opinión, debería cambiarse: ¿por qué asumir la sincronía cuando el navegador no lo es? En realidad, soy de la opinión de que tanto RequireJS como CommonJS deberían tener una implementación prometedora incorporada.
I-Lin Kuo
Ambos formatos son rutas válidas a Módulos CommonJS / 2.0 y proporcionan la misma escalabilidad. En cuanto a mí, tratar con CJS Modules / 1.1 (eso es lo que quiero decir con CommonJS) es mucho más fácil, el código se ve más limpio.
Dmitry Sheiko
He conocido beneficios de AMD como: * puede cargar más que solo archivos JavaScript; * alias de ruta; Bueno, CommonJS Compiler resuelve estos: carga dependencias que no son JavaScipt / JSON como datos y se puede proporcionar con la configuración de compilación (incluidos los alias). La única desventaja que requiere construir. Pero hoy en día todo el mundo construye el proyecto para preprocesadores CSS. Entonces se trata de agregar una tarea extra para Grunt / Gulp ...
Dmitry Sheiko