En el mundo de javascript existen muchas facilidades de programar, el único detalle es abusar de sus facilidades. Al final uno obtiene variables y funciones repartidas a lo largo de todo el código y sin un orden, lo que termina siendo inmantenible. Una de las mejores practicas a la hora de escribir código es usar los patrones de diseño en javascript y el más utilizado es el patròn modular.
En javascript el patrón modular emula el concepto de clases, de manera que somos capaces de incluir métodos públicos/privados y propiedades dentro de un único objeto, protegiendo las datos particulares del ámbito global, lo que ayuda a evitar la colisión de nombres de funciones y variables ya definidas a lo largo de nuestro proyecto, o API’s de terceros, a continuación unos conceptos previos para poder entender mejor el patrón modular.
EL patrón modular se basa en parte en los objetos literales por ende es importante entenderlo. Un objeto literal es descrito como cero o más pares nombre/valor, separados por comas entre llaves. Los nombres dentro del objeto pueden ser cadenas o identificadores que son seguidas por 2 puntos, dichos objetos también pueden contener otros objetos y funciones.
varobjetoLiteral={/* los objetos literales pueden contener propiedades y métodos */saludo : "soy un objeto literal",miFuncion : function(){// código}};/* accediendo a una propiedad de nuestro objeto literal persona */objectLiteral.saludoUn ejemplo de un módulo usando un objeto literal.
varpersona={/* definiendo propiedades */nombre : "adan",edad : 33,/* método simple */comer : function(){console.log(this.nombre+" esta comiendo.");}};/* accediendo al método comer de nuestro objeto literal persona */persona.comer();Un módulo es una unidad independiente funcional que forma parte de la estructura de una aplicación. Podemos usar funciones y closures(cierres) para crear módulos.
varmodulo=(function(){//- - -});Un ejemplo más completo:
varautomovil=(function(colorDeAuto){varcolor=colorDeAuto;return{avanzar : function(){console.log("el auto "+color+" esta avanzando");},retroceder : function(){console.log("el auto "+color+" esta retrocediendo");}}})("azul");/* accediendo los metodos retroceder y avanzar de nuestro módulo */automovil.retroceder();automovil.avanzar();Las funciónes anónimas son funciónes sin nombre, comúnmente asociados a una variable.
varmiFuncionAnonima=function(){alert("Hola mundo!");};miFuncionAnonima();Estas funciónes una vez declaradas se llaman a sí mismas para inicializarse, los primeros paréntesis encierran el contenido, los segundos paréntesis asumen que el interior de los primeros paréntesis es una función y la ejecuta inmediatamente.
/* 01 */(function(){alert("Hello World!");})();/* 02 */varmyAnonymousFunction=(function(){alert("Hello World!");})();/* 03 */varmyAnonymousFunction=(function(message){alert(message);})("hello world");// todo lo que le precede a los 2 últimos paréntesis se ejecuta inmediatamenteLos clousures son funciones definidas dentro de otras funciones, así mismo dicha función interna tiene acceso al ámbito de la función contenedora.
functionejemploClousure(arg1,arg2){varlocalVar=8;functionmultiplicador(interArg){returnarg1*arg2*interArg*localVar;}/* retornar una referencia de la función interna definida como: multiplicador */returnmultiplicador;}/* la función devuelve una función, por lo tanto necesita asignación */varglobalVar=ejemploClousure(2,4);/* y luego llamar a */globalVar(8);Los métodos privados son funciones que no pueden ser llamados desde fuera del ámbito donde han sido declarados, dichos métodos podrán ser invocados en nuestros métodos públicos.
varmodulo=(function(){varprivateMethod=function(message1){console.log(message1);};varpublicMethod=function(mensaje2){privateMethod(mensaje2);};return{publicMethod: publicMethod};})();/* pasando datos a un método privado */modulo.publicMethod("mi mensaje");Comúnmente los módulos retornan un objeto, la cual los métodos ligados a dicho objeto serán accesibles desde fuera del módulo.
varmodule=(function(){/* simple método privado */varprivateMethod=function(){console.log("soy un método privado");};/* retornando un objeto literal */return{publicMethod : function(){privateMethod();console.log("soy un método publico");}}})();/* accediendo nuestro método publico */module.publicMethod();- Código limpio , separado y organizado.
- Soportan datos privados.
- Código Escalable.
Bien, ahora que ya tenemos los algunos conceptos definidos vamos a realizar un ejercicio la cual sera realizar tabs, con una estructura mas avanzada, vamos a realizarlo con jquery.
<ulclass="tabs"><liclass="tabs_item"><aclass="tabs_item_target is_selected" data-tab="tab_one">JavaScript</a></li><liclass="tabs_item"><aclass="tabs_item_target" data-tab="tab_two">Html5</a></li><liclass="tabs_item"><aclass="tabs_item_target" data-tab="tab_three">Css</a></li></ul><divclass="tabs_content"><divid="tab_one" class="tabs_content_pane is_active">
contenido JavaScript
</div><divid="tab_two" class="tabs_content_pane">
contenido Html5
</div><divid="tab_three" class="tabs_content_pane">
contenido Css
</div></div>A continuación se muestra una estructura modular mas avanzada y explicaremos paso a paso las partes que la componen.
// Definimos la variable tabs la cual contendrá todo nuestro modulo.vartabs=(function(){// Objeto la cual establecemos valores que vamos a usar mas adelante en este ámbito.varst={//- - -};// Objeto vacío que guardará elementos que se manejan por HTML.vardom={}// Función que llenará al objeto dom con los objetos HTML a través de jQuery ($).varcatchDom=function(){//- - -};// Función donde establecemos los eventos que tendrán cada elemento.varsuscribeEvents=function(){//- - -};/* Objeto que guarda métodos que se van a usar en cada evento definido en la función suscribeEvents. */varevents={//- - -};// Función que inicializará los funciones decritas anteriormente.varinitialize=function(){//- - -};/* Retorna un objeto literal con el método init haciendo referencia a la función initialize. */return{init:initialize}})();// Ejecutando el método "init" del módulo tabs.tabs.init();Finalmente luego de haber entendido nuestra estructura anterior, procedemos a la creación de nuestro modulo tabs.
vartabs=(function(){varst={tabs : '.tabs',tabs_item : '.tabs_item',tabs_item_target : '.tabs_item_target'};vardom={}varcatchDom=function(){dom.tabs_item_target=$(st.tabs_item_target,st.tabs);};varsuscribeEvents=function(){dom.tabs_item_target.on('click',events.eSelectedTab);};varevents={eSelectedTab: function(e){self=$(this);self.addClass('is_selected');varbrother=self.parent(st.tabs_item).siblings();$(st.tabs_item_target,brother).removeClass('is_selected');varpane=self.attr('data-tab');$("#"+pane).addClass('is_active');$("#"+pane).siblings().removeClass('is_active');}};varinitialize=function(){catchDom();suscribeEvents();};return{init: initialize}})();tabs.init();http://addyosmani.com/resources/essentialjsdesignpatterns/book/#modulepatternjavascriptthttps://www.safaribooksonline.com/library/view/javascript-the-good/9780596517748/
Si deseas probar la demo del ejemplo, ejecutar:
npm install
node server
Lo podrás visualizar en.
localhost:4000
Si tienes conflictos con el puerto modificar en server.js, el primer parámetro del metodo listen y cambiarlo por un puerto que tenga disponible.
app.listen(4000,function(){console.log('server ready!');});