Patrón Módulo con Namespace en Javascript

Introducción

Javascript cada vez es más popular entre los desarrolladores. Están apareciendo nuevos frameworks para utilizarlo de formas que hace unos años ni siquiera hubiéramos imaginado. Knockout, Backbone, Ember, Angular.js hasta podemos ejecutarlo en servidores con node.js o Rhino. Además, los navegadores tienen interpretes mas sofisticados e incluso compiladores para transformar el Javascript interpretado y mejorar el rendimiento en las ejecuciones.

Pero, ¿qué pasa cuando nuestro código crece?, ¿cómo lo estructuramos?,  ¿cómo evitamos colisiones con el Javascript que ya tenemos escrito?

Patrón módulo en Javascript

Podemos encontrar una definición formal de este patrón en la wikipedia: Patrón Módulo.Patrón Módulo con Namespace en Javascript

Un módulo es una agrupación de conceptos relacionados entre sí y que pueden exponer algunas de sus partes al exterior. En lenguajes orientados a objetos como Java y .Net podemos implementar módulos con clases.

 

¿Cómo declaramos un módulo en Javascript?

Para crear un módulo necesitamos definirlo como una función:

var SimpleGameModule = function () {
   //Código del módulo
};


Para crear una instancia de nuestro nuevo módulo solo tenemos que ejecutar:

var objGame = new SimpleGameModule();

Si no queremos crear instancias de nuestro módulo y queremos tenerlo disponible desde el inicio,  tenemos que declararlo como una función autoejecutable. Fijaros en “()” después de la llave de cierre del módulo: eso hace que cuando el intérprete de Javascript lea la función, directamente la ejecute.

var SimpleGameModule = (function(){
   //Código del módul
})();

 ¿Cómo crear un Namespace?

Cuando nuestras aplicaciones crezcan tendremos muchos módulos que necesitaremos organizar. Los Namespaces nos ayudan organizar nuestros módulo en grupos funcionales.

Declarar un módulo en javascript es tan sencillo como crear una variable:

var GammingNamespace = {};

¿Cómo añadir nuestro módulo al Namespace?

Para utilizar nuestro patrón módulo con namespace en javascript, primero tenemos que declarar nuestro namespace.

Después tenemos que  incluir nuestro módulo en una función autoejecutable que recibe como parámetro el namespace.

Por último pasamos nuestro namespace como parámetro de la función autoejecutable.

var GammingNamespace = {};
(function (ns) {
   use strict;

   //Constructor
   var SimpleGameModule = function () {
      //Código del módulo
   };

   //Publicamos el módulo en el namespace
   ns.SimpleGameModule = SimpleGameModule;
}(window.GammingNamespace || {}));

En el caso de que nuestro Namespace no esté declarado, el módulo dará un error. Como medida de seguridad  pasamos “{}” y así nuestro código seguirá funcionando.

Ahora nuestro módulo no es visible desde el contexto global: solo está disponible dentro del Namespaces “GammingNamespace”.

var objGame = new GammingNamespace.SimpleGameModule();

¿Cómo declaramos atributos privados en nuestro módulo?

Los atributos privados tenemos que declararlos en el constructor de nuestro módulo, dentro del objeto this. 

var GammingNamespace = {};
(function (ns) {
   use strict;

   //Constructor
   var SimpleGameModule = function () {
      //Atributos de la instancia
      this.score;
   };

   //Publicamos nuestro módulo en el namespace
   ns.SimpleGameModule = SimpleGameModule;
}(window.GammingNamespace || {}));

Estos atributos solo serán visibles dentro del módulo. Si ejecutáramos el módulo e intentamos acceder a alguno de los atributos, recibiríamos un “undefined”:

var objGame = new GammingNamespace.SimpleGameModule();
objGame.score

¿Cómo declaramos métodos privadas?

var GammingNamespace = {};
(function (ns) {
   use strict;

   //Constructor
   var SimpleGameModule = function () {
      //Atributos de la instancia
      this.score;
      _InitializeGame.call(this);
   };

   //Funciones privadas
   var _InitializeGame = function () {
      this.score = 0;
   };

   //Publicamos nuestro módulo en el namespace
   ns.SimpleGameModule = SimpleGameModule;
}(window.GammingNamespace || {}));

 

¿Cómo declaramos métodos y atributos públicos?

Para crear métodos o atributos públicos tenemos que encapsularlos dentro de la propiedad prototype de nuestro módulo:

var GammingNamespace = {};
(function (ns) {
   use strict;

   //Constructor
   var SimpleGameModule = function () {
      //Atributos de la instancia
      this.score;
      _InitializeGame.call(this);
   };

   //Funciones privadas
   var _InitializeGame = function () {
      this.score = 0;
   };

   //Funciones públicas
   SimpleGameModule.prototype = {
      AddScore : function (point) {
         this.score += point;
      },
      GetScore : function () {
         return "Tu puntuación es: " + this.score;
      }
   }

   //Publicamos nuestro módulo en el namespace
   ns.SimpleGameModule = SimpleGameModule;
}(window.GammingNamespace || {}));

Encapsulamos todos los métodos públicos sobrescribiendo el atributo prototype para optimizar el “minificado” del fichero.

Como la palabra prototype es reservada del lenguaje, si creáramos cada método publico individualmente en el prototype, no podríamos “minificar” esas líneas. Si tenemos muchos métodos públicos estaremos perdiendo ratio de compresión.

//Public Prototype
GammingNamespace.prototype.AddScore: function (points) {
   this.score += points
}
GammingNamespace.prototype.GetScore: function () {
   return this.score;
}

Si vamos a utilizar herencia para nuestro módulo tenemos que declarar cada método individualmente en el prototype. Esto lo explicaremos en el post dedicado a la herencia en javascript.

¿Cómo trabajo con el patrón módulo con namespace en Javascript?

Solo tenemos que crear una instancia de nuestro módulo y utilizar sus métodos públicos:

var objGame = new GammingNamespace.SimpleGameModule();
objGame.GetScore();
objGame.AddScore(10);
objGame.GetScore();

¿Cómo usar objectos del contexto global en nuestros módulos?

En muchos casos tendremos que acceder a objetos globales desde nuestro módulo, por ejemplo al objecto “window” o “jQuery”. Una buena práctica para encapsular totalmente nuestros módulos es pasar estos objectos como parámetros a nuestro módulo. Dentro de nuestro módulo guardaremos una copia de estos objectos. De esta forma solo utilizaremos objectos internos del módulo y ganaremos algo de rendimiento, porque cada vez que queramos acceder a “jQuery” o al objecto “window” lo haremos en nuestra copia local y no tendremos que acceder al contexto global del navegador.

var GammingNamespace = {};
(function (ns, jQuery, window) {
   use strict;

   var _$ = jQuery;
   var _window = window;

   //Constructor
   var SimpleGameModule = function () {
      //Atributos de la instancia
      this.score;
      _InitializeGame.call(this);
   };

   //Funciones privadas
   var _InitializeGame = function () {
      this.score = 0;
   };

   //Funciones públicas
   SimpleGameModule.prototype = {
      AddScore : function (point) {
         this.score += point;
      },
      GetScore : function () {
         return "Tu puntuación es: " + this.score;
      }
   }

   //Publicamos nuestro módulo en el namespace
   ns.SimpleGameModule = SimpleGameModule;
}(window.GammingNamespace || {}, window, jQuery));

Ventajas de este patrón

  • Encapsulación de nuestras funciones.
  • Evitamos colisión con otros desarrollos.
  • Mostrar solo la parte pública de nuestros desarrollos.

Desventajas de este patrón

  • Si queremos cambiar un método de público a privado o viceversa tenemos que modificar el módulo y mover los métodos. Esta desventaja se puede solucionar utilizando: Revealing Module Pattern.

 

¿Cómo afecta al rendimiento este patrón?

Hemos comparado el rendimiento de este patrón con otras formas de encapsular funcionalidades en javascript:

Los resultados se pueden ver en jsperf.com

En muchos casos, la versión “Object literal notation” tiene un mejor rendimiento, pero hay que tener en cuenta que en estas pruebas estamos haciendo cientos de miles de ejecuciones. Por lo tanto, en una aplicación estandard, el rendimiento de estos patrones es similar.

Para más información sobre el consumo de memoria y el rendimiento de este patrón podéis consultar el artículo: Javascript Module Pattern, Memory, Closures

Nos vemos por la red!

11 Comments


  1. The very next time I read a blog, I hope that it won’t disappoint me as much as this particular one. I mean, I know it was my choice to read through, but I actually believed you’d have something helpful to talk about. All I hear is a bunch of complaining about something you could possibly fix if you weren’t too busy looking for attention.

    Reply

  2. Everything is very open with a precise clarification of the challenges. It was really informative. Your website is very helpful. Many thanks for sharing!

    Reply

  3. I just want to say I am just all new to blogs and absolutely enjoyed you’re web page. Most likely I’m planning to bookmark your blog . You definitely have excellent articles and reviews. With thanks for revealing your web page.

    Reply

  4. Article writing is also a fun, if you be acquainted with after that you can write or else it is difficult to
    write.

    Reply

  5. I similar to the valuable info you provide on your articles.
    I will bookmark your blog and check out again on this site regularly.
    I am fairly sure I will be told a lot of new stuff proper
    here! Good luck for these!

    Reply

  6. My spouse and I absolutely love your blog and find
    most of your post’s to be just what I’m looking for.
    Would you offer guest writers to write content for you personally?
    I wouldn’t mind publishing a post or elaborating on many of the subjects you write concerning here.

    Again, awesome web log!

    Reply

  7. I simply want to say I’m all new to blogging and site-building and definitely loved this blog. Likely I’m planning to bookmark your site . You surely have impressive article content. Many thanks for sharing with us your web site.

    Reply

  8. My brother suggested I would possibly like this website. He used to
    be totally right. This submit actually made my day.
    You can not believe simply how a lot time I had spent for this info!
    Thanks!

    Reply

  9. Excellent strategy for telling, and good article to obtain information concerning my presentation subject,
    which i will deliver in university.

    Reply

  10. Article writing can be another fun, when you know then you are able to write if not it really is difficult to
    publish.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *