Find me on medium
Join my newsletter
In JavaScript, a widely used and powerful pattern is the Module Pattern. It can be incredibly simple to implement but the fact that it enables developers to encapsulate their code makes it one of the most versatile patterns to build robust code. When you look inside the source code of JavaScript libraries, you're most likely looking at an implementation of this pattern. In addition, they're also most likely a singleton object--where only one instance exists throughout the lifetime of an app.
It may be difficult for newcomers in JavaScript to understand the module pattern as there are several variations that exist. However, it's worth all the time and trouble because you'll be using the module pattern to write most of your apps once you've understood the concept.
Variations
Immediately Invoked Function Expression
Arguably the most popular variation of the module pattern is the IIFE (Immediately Invoked Function Expression). These are essentially functions that invoke immediately and should return an object (an interface, in other words), which will be used as the module.
Inside these functions are code that is private and accessible only within that function's scope unless the returned interface (publicly accessible by the outside world) provides methods that can access them somehow.
Modules
As you may have guessed, the module pattern lets you create modules.
We will implement our own module using the IIFE. This allows us to assign the return value of an IIFE directly onto a variable so that we can use it just like a JavaScript module.
For example, lets pretend that we are creating an RPG game and the first thing we decided to do was create a sorceress class. The sorceress will have methods to inflict damage to their targets. In just about every RPG game, sorceresses usually cast spells or magic, so we'll define an interface that mimic this concept:
const sorceress = (function() {
const sideEffects = {
intervals: {},
}
function _fireBolt(target, customDamage) {
target.hp -= customDamage !== undefined ? customDamage : 15
}
function _thunderBolt(target) {
target.hp -= 15
}
function blizzard(target) {
target.hp -= 15
}
function _applyThunderBoltSideEffects(
target,
{ interval = 1000, timeout = 15000 } = {},
) {
if (sideEffects.intervals[target.id]) {
clearInterval(sideEffects.intervals[target.id])
}
sideEffects.intervals[target.id] = setInterval(() => {
target.hp -= 1
}, interval)
setTimeout(() => {
if (sideEffects.intervals[target.id]) {
clearInterval(sideEffects.intervals[target.id])
}
}, timeout)
}
return {
fireBolt(target, options) {
if (options) {
_fireBolt(target, options.customDamage)
} else {
_fireBolt(target)
}
},
thunderBolt(target) {
_thunderBolt(target)
_applyThunderBoltSideEffects(target)
},
blizzard,
}
})()
In this example, our sorceress class has three methods: sorceress.fireBolt
, sorceress.thunderBolt
, and sorceress.blizzard
.
Inside the module, we declared three private functions and one public function. We can obviously tell that that the functions prefixed with underscores _
are the private functions while the others are public. This isn't how we create public and private code inside though, we do it by what's being returned using closure. We returned an object which is exposed to the caller. Having the power to declare private and public variables is what makes the module pattern one of the most powerful patterns in JavaScript.
By keeping things private we can prevent code from being revealed to the "outside world".
Find me on medium
Join my newsletter
Top comments (4)
Can you elaborate as if I am five?
I was about to write an elaborate explanation, but Douglas Crockford already wrote an extensive article about this 😄:
crockford.com/javascript/private.html
The keyword is "closure", an example is visible in a constructor-function:
When a Person is created we can call
introduce
on it, but not fullName, essentially making fullName private.Keep in mind, closures are not limited to constructors! A closure is defined as "a function with its variable scope". Simplified that means that a function 'remembers' the scope it was defined in.
I hope it helps!
For more info you can check developer.mozilla.org/en-US/docs/W...
There is probably a mistake in the title - the pattern described is a revealing module pattern, not the mediator, which essentially is an extension of the observable pattern (in a sense Mediator acts as both an observable [publishing to subscribers] and an observer [receiving messages from subscribers] )
Are the Mediator pattern and module pattern the same ?