JavaScript Module Pattern

The JavaScript Module Pattern provides structure, organization and protection to self-contained pieces of code by utilizing other common design patterns such as: Immediate Invoke Function Expressions(IIFE), Closures, and Namespace. Let's take a look at how these techniques work together to help us organize our code.


The Immediately Invoked Function Expression (IIFE)

The Immediately Invoked Function Expression pattern executes a function as soon as it is defined. This can be named or anonymous and it consists of the function () expression, wrapped in parentheses, and another set of parentheses () at the end, which causes the function to be executed immediately.

(function () { //code })()

There are several variations for Immediately Invoked Functions. For example: The ! and + before the function makes it to be treated as an expression, so we can call it with the () at the end without the extra set of parentheses wrap around the function. These two patterns below are generally used if you are concatenating multiple files with multiple modules together. They will help to avoid errors if previously concatenated modules missed a trailing semicolon ; to end the function.

!(function () { //code })()
+(function () { //code })()

In addition, IIFE's define a new scope, this prevents global scope pollution or name collisions and enables you to safely wrap individual features into self-contained modules.

var yourModule = (function () { //code })()

Private Methods

In JavaScript we can implement privacy using closures. A JS closure is essentially a function declaration inside another function. The goal is to hide the variable accessibility from the global scope. In the following example var privateMethod has a closure over the scope of var yourModule.

var yourModule = (function () { var privateMethod = function () { //private code } })()

On the following example, privateMethod is part of the yourModule scope. The privateMethod properties are not accessible outside the yourModule, they are private. However, we can access the properties of privateMethod with utilizing return. This bounds a public object and makes the privateMethod properties accessible via the module's namespace. This is how we access Private Methods.

var yourModule = (function () { var privateMethod = ["Eric", "Kenny", "Stan", "Kyle"] return { publicMethod: function (boy) { return privateMethod[boy] }, } })() console.log(yourModule.publicMethod(3)) //Kyle console.log(yourModule.privateMethod) //undefined console.log(yourModule.privateMethod(3)) // TypeError: yourModule.privateMethod is not a function

Revealing Module Pattern

The Revealing Module is on the most common way of implementing the module pattern. Let's examine the code block below. First, we have an IIFE, this creates a new scope and the Music module's closure. Second, the object we return has references on it to inner functions. But not to the inner data variables. Those variable are hidden and private.

var Music = (function () { var genre = "Rock" var records = ["Dark Side of the Moon", "Jazz from Hell", "Bird Cage"] var privateCollection = ["Philip Glass", "Terry Riley"] var privateLibrary = function () { console.log(privateCollection) //private } var getGenre = function () { console.log(genre) //public } var getRecords = function () { console.log(records) //public } return { getGenre: getGenre, getRecords: getRecords, } })() Music.getGenre() Music.getRecords()

Namespacing

Namespacing is a technique used to avoid name collisions with other objects or variables in the global scope. As your code grows the probabilities of name collisions on methods, variables or objects are higher. This can result in an unexpected outcome. Namespacing can help tackle this problem providing data protection. In addition Namespacing helps organize your application into easily identifiable code blocks.

The key for namespace is creating an object, by convention the name of this wrapper object is capitalize entirely.

var YOURMODULE = {}

Now, we have to reference the YOURMODULE object to access the properties.

var YOURMODULE = { second: function () { console.log("hello world") // hello world }, init: function () { this.second() }, } YOURMODULE.init()

Nested Namespacing is very common in the module pattern because the level of protection and organization that it provides. In the example below SECOND namespace is a property of FIRST namespace and it's passing in a list variable that incorporates the first namespace.

var FIRST = { list: ["Chef", "Kenny", "Stan"], SECOND: { members: function (elm) { var listTwo = [] for (var i = 0; i < elm.length; i++) { var item = elm[i] listTwo.push(item) } console.log(listTwo) }, }, } FIRST.SECOND.members(FIRST.list)

As the complexity of your application grows and different files are included conditionally, we need to take extra caution with our namespace and properties to avoid any overwriting. Before adding a property or creating a namespace it's best to check that it doesn't exits already, as shown in the example below:

var FIRST = FIRST || {}

Adding Modules

First, let's take a look at coolModuleTwo. The coolObject serves a container, it is an object literal and we can add properties to it. createMember and removeMember methods are properties of coolObject, and by returning its object we make those methods public. coolModuleOne uses the Revealing Module pattern, by passing this object to coolModuleTwo we have access to this module.

var ModuleOne = (function () { var sayHello = function () { console.log("Howdy Ho!") } var sayGoodBye = function () { console.log("GoodBye") } return { sayHello: sayHello, sayGoodBye: sayGoodBye, } })()
var ModuleTwo = (function (ModuleOne) { ModuleOne.sayHello() ModuleOne.sayGoodBye() var coolObject = {} coolObject.createMember = function () { console.log("CREATE SOMEONE") } coolObject.removeMember = function () { console.log("REMOVE SOMEONE") } return coolObject })(ModuleOne || {}) ModuleTwo.createMember() //CREATE SOMEONE ModuleTwo.removeMember() //REMOVE SOMEONE