The Wayback Machine - https://web.archive.org/web/20110319090223/http://answers.oreilly.com:80/topic/2177-how-to-use-the-module-pattern-in-javascript/

Jump to content

How to use the Module Pattern in JavaScript

+ 2
 
chco's Photo
Posted Oct 28 2010 03:37 PM

This excerpt from Javascript Patterns explains how to write modules in Javascript to help you structure your code and make it easier to maintain.
The module pattern is widely used because it provides structure and helps organize your code as it grows. Unlike other languages, Javascript doesn’t have special syntax for packages, but the module pattern provides the tools to create self-contained decoupled pieces of code, which can be treated as black boxes of functionality and added, replaced, or removed according to the (ever-changing) requirements of the software you’re writing.

The module pattern is a combination of several patterns, namely:

  • Namespaces

  • Immediate functions

  • Private and privileged members

  • Declaring dependencies


The first step is setting up a namespace. Let’s use the namespace() function from earlier in this chapter and start an example utility module that provides useful array methods:

MYAPP.namespace('MYAPP.utilities.array');


The next step is defining the module. The pattern uses an immediate function that will provide private scope if privacy is needed. The immediate function returns an object—the actual module with its public interface, which will be available to the consumers of the module:

MYAPP.utilities.array = (function () { return { // todo... }; }());


Next, let’s add some methods to the public interface:

MYAPP.utilities.array = (function () { return { inArray: function (needle, haystack) { // ... }, isArray: function (a) { // ... } }; }());


Using the private scope provided by the immediate function, you can declare some private properties and methods as needed. Right at the top of the immediate function will also be the place to declare any dependencies your module might have. Following the variable declarations, you can optionally place any one-off initialization code that helps set up the module. The final result is an object returned by the immediate function that contains the public API of your module:

MYAPP.namespace('MYAPP.utilities.array'); MYAPP.utilities.array = (function () { // dependencies var uobj = MYAPP.utilities.object, ulang = MYAPP.utilities.lang, // private properties array_string = "[object Array]", ops = Object.prototype.toString; // private methods // ... // end var // optionally one-time init procedures // ... // public API return { inArray: function (needle, haystack) { for (var i = 0, max = haystack.length; i < max; i += 1) { if (haystack[i] === needle) { return true; } } }, isArray: function (a) { return ops.call(a) === array_string; } // ... more methods and properties }; }());


The module pattern is a widely used and highly recommended way to organize your code, especially as it grows.

Revealing Module Pattern

We already discussed the revelation pattern in this chapter while looking at the privacy patterns. The module pattern can be organized in a similar way, where all the methods are kept private and you only expose those that you decide at the end, while setting up the public API.

The above can become:

MYAPP.utilities.array = (function () { // private properties var array_string = "[object Array]", ops = Object.prototype.toString, // private methods inArray = function (haystack, needle) { for (var i = 0, max = haystack.length; i < max; i += 1) { if (haystack[i] === needle) { return i; } } return −1; }, isArray = function (a) { return ops.call(a) === array_string; }; // end var // revealing public API return { isArray: isArray, indexOf: inArray }; }());


Modules That Create Constructors

The preceding example produced an object MYAPP.utilities.array, but sometimes it’s more convenient to create your objects using constructor functions. You can still do that using the module pattern. The only difference is that the immediate function that wraps the module will return a function at the end, and not an object.

Consider the following example of the module pattern that creates a constructor function MYAPP.utilities.Array:

MYAPP.namespace('MYAPP.utilities.Array'); MYAPP.utilities.Array = (function () { // dependencies var uobj = MYAPP.utilities.object, ulang = MYAPP.utilities.lang, // private properties and methods... Constr; // end var // optionally one-time init procedures // ... // public API -- constructor Constr = function (o) { this.elements = this.toArray(o); }; // public API -- prototype Constr.prototype = { constructor: MYAPP.utilities.Array, version: "2.0", toArray: function (obj) { for (var i = 0, a = [], len = obj.length; i < len; i += 1) { a[i] = obj[i]; } return a; } }; // return the constructor // to be assigned to the new namespace return Constr; }());


The way to use this new constructor will be like so:

var arr = new MYAPP.utilities.Array(obj);


Importing Globals into a Module

In a common variation of the pattern, you can pass arguments to the immediate function that wraps the module. You can pass any values, but usually these are references to global variables and even the global object itself. Importing globals helps speed up the global symbol resolution inside the immediate function, because the imported variables become locals for the function:

MYAPP.utilities.module = (function (app, global) { // references to the global object // and to the global app namespace object // are now localized }(MYAPP, this));


Cover of Javascript Patterns
Learn more about this topic from Javascript Patterns. 

What's the best approach for developing an application with Javascript? This book helps you answer that question with numerous Javascript coding patterns and best practices. If you're an experienced developer looking to solve problems related to objects, functions, inheritance, and other language-specific categories, the abstractions and code templates in this guide are ideal -- whether you're writing a client-side, server-side, or desktop application with Javascript. Author Stoyan Stefanov includes several examples for each pattern as well as practical advice for implementing them.

Learn MoreRead Now on Safari


Tags:
1 Subscribe


1 Reply

0
  =Bill.Barnhill's Photo
Posted Nov 05 2010 04:47 AM

More a question than an alternate solution...

This looks very interesting and I plan to pick up the book.

How would you do inheritance using the module pattern? My guess is you export a public function from the module that uses Object.create, similar to the following from this prototypal-inheritance article :

 Object.spawn = function (parent, props) { var defs = {}, key; for (key in props) { if (props.hasOwnProperty(key)) { defs[key] = {value: props[key], enumerable: true}; } } return Object.create(parent, defs); } 


Except you'd make the module the parent. Would that work and what's the best way to do it so you're not redoing that function in every module? If it helps I am looking specifically at a node.js environment at the moment.

close