About
This article shows classic design pattern with ECMAScript on how to organize javascript code with a structure that make possible to:
- get input
- return output
- and hide the implementation from the outside world
This structure is known globally as a module in javascript.
The early JavaScript implementation (such as ECMA-262 1)) add no means to organize code such as ESM module, this pattern were then found by developers to organize their code.
Patterns
Module pattern based on IIFE / Anonymous Closure
The Immediately invoked function expression (IIFE) is a common pattern that :
- permits to not pollute the global variable (all body vars and functions are in the function scope and not in the global)
- permits to access to all globals
- permits to pass global variable
- permit to export by returning
IIFE are also known as Anonymous Closure.
This pattern are also known as the module pattern
Import with argument
You can import via the argument.
For instance, if you want to have access to the global variable JQuery
(function ($) {
// now have access to globals jQuery (as $)
}(jQuery));
Export with Return
Example:
let module = (function () {
let exp = {}; // the public object that will be returned
let privateVariable = 1; // this variable stays in the function scope and is then private
// this function stays in the function scope and is then private
function privateMethod() {
// ...
}
exp.publicProperty = "public property !"; // the attached property is also public
exp.publicMethod = function () {
console.log("public method");
};
return exp;
}());
- We can then use it
module.publicMethod();
console.log(module.publicProperty);
Augmentation / Overwrite
var GLOBAL_MODULE = (function (module) {
// Augmentation
module.newFunction= function(){
console.log("new function !")
}
// Overwrite
let oldOverwrittedMethod= module.overwrittedMethod;
module.overwrittedMethod = function(){
console.log("overitted method with access to the old method");
}
return module;
}(GLOBAL_MODULE || {}));
- Usage
GLOBAL_MODULE.newFunction();
The definition of the GLOBAL_MODULE with var is important because it allows to pass it as argument even if it was not defined. If you use let or const, you would get the following error: Cannot access 'GLOBAL_MODULE' before initialization
SubModule
The returned object of the IIFE becomes a property of the module.
MODULE.sub = (function () {
var my = {};
// ...
return my;
}());
Object literal pattern based on function and class
Normal function with closure
A normal function can also be used.
This design pattern makes possible to implement a class (object) with the help of the closure capability of the Javascript function.
The function will behaves like a class but in a function structure.
The call to a module function will instantiate a new function with a new scope.
function User(name){
// Private
var username = name;
// Private
function returnName() {
return username;
}
// Public
var publicAPI = {
getName: returnName
};
return publicAPI;
}
// User() creates an instance of the User module
var foo = User("foo");
var bar = User("bar");
console.log( foo.getName()+" loves "+bar.getName() );
The new keyword was not used (ie new User()) because User is not a class to be instantiated, User() is just a function.
Class
class are by default good candidate for module creation.