2. The Module Pattern

Created Thursday 19 December 2013

  1. Several options for implementing modules:
    1. The module pattern
    2. Object literal notation
    3. AMD modules
    4. CommonJS modules
    5. ECMAScript Harmony modules
  2. Object literals:
    1. Example of module defined using object literal notation:
var myModule = {
myProperty: "someValue",
myConfig: {
useCaching: true,
language: "en"
},
saySomething: function() {
console.log("Some string");
},
reportMyConfig: function() {
console.log("Caching is: " + (this.myConfig.useCaching ? "enabled" : "disabled"));
},
updateMyConfig: function(newConfig) {
if (typeof newConfig === "object") {
this.myConifg = newConfig;
console.log(this.myConfig.language);
}
}
};
myModule.saySomething();
myModule.reportMyConfig();
myModule.updateMyConfig({
language: "fr",
useCaching: false
});
myModule.reportMyConfig();
  1. In-depth about organizing code with object literals:
    1. http://rmurphey.com/blog/2009/10/15/using-objects-to-organize-your-code/

  1. Module pattern uses object literals only as the return value from a scoping function
  2. Some reading about "immediately-invoked functional expression":
    1. http://benalman.com/news/2010/11/immediately-invoked-function-expression/
  3. Example of the Module pattern implementation:
var testModule = (function() {
var counter = 0;
return {
incrementCounter: function() {
return counter++;
},
resetCounter: function() {
console.log("counter value prior to reset: " + counter);
}
};
})();
// The counter variable is fully shielded from global scope, hence it's private
// Usage
testModule.incrementCounter();
testModule.resetCounter();
  1. Simple template for the Module pattern:
var myNamespace = (function() {
var myPrivateVar, myPrivateMethod;
// A private counter variable
myPrivateVar = 0;
// A private function which logs any arguments
myPrivateMethod = function(foo) {
console.log(foo);
};
return {
// A public variable
myPublicVar: "foo",
// A public function utilizing privates
myPublicFunction: function(bar) {
// Increment our private counter
myPrivateVar++;
// Call our private method using bar
myPrivateMethod(bar);
}
};
})();
  1. More complex example:
var basketModule = (function() {
// privates
var basket = [];
function doSomethingPrivate() {
//...
}
function doSomethingElsePrivate() {
//...
}
// Return an object exposed to the public
return {
// Add items to our basket
addItem: function(values) {
basket.push(values);
},
// Get the count of items in the basket
getItemCount: function() {
return basket.length;
},
// Public alias to a private function
doSomething: doSomethingPrivate,
// Get the total value of items in the basket
getTotal: function() {
var q = this.getItemCount(),
p = 0;
while (q--) {
p += basket[q].price;
}
return p;
}
};
})();
// basketModule returns an object with a public API we can use
basketModule.addItem({
item: "bread",
price: 0.5
});
basketModule.addItem({
item: "butter",
price: 0.3
});
// Outputs: 2
console.log(basketModule.getItemCount());
// Outputs: 0.8
console.log(basketModule.getTotal());
// Won't work (basket is out of the public API)
console.log(basketModule.basket);
// Won't work (basket exists only within the scope of our basketModule closure)
console.log(basket);
  1. Module pattern variations:
    1. Import (example for globals like jQuery and Underscore):
// Global module
var myModule = (function(jQ, _) {
function privateMethod1() {
jQ(".container").html("test");
}
function privateMethod2() {
console.log(_.min([10, 5, 100, 2, 1000]));
}
return {
publicMethod: function() {
privateMethod1();
}
};
})(jQuery, _);
  1. Exports (declare globals without consuming them):
// Global module
var myModule = (function() {
// Module object
var module = {},
privateVariable = "Hello World";
function privateMethod() {
//...
}
module.publicProperty = "Foobar";
module.publicMethod = function() {
console.log(privateVariable);
};
return module;
})();



Backlinks: