The Module Pattern in JavaScript
June 06, 2016
Let’s talk about organizing our code. There’s never just one way to accomplish something with code. This is both great, and sort of paralyzing. How do you choose?
Design patterns
Design patterns in JavaScript are documented approaches — or frameworks — for solving problems and structuring code. They are tried and true, reusable, and improve readability — for yourself and others reading your code.
From Addy Osmani’s “Learning JavaScript Design Patterns“–
A pattern is a reusable solution that can be applied to commonly occurring problems in software design – in our case – in writing JavaScript web applications.
Patterns are not an exact solution. It’s important that we remember the role of a pattern is merely to provide us with a solution scheme.
The module pattern is one such pattern. Before we look at this pattern, let’s very briefly refresh on the concept of closure.
Closure
A closure is when a function remembers the context in which it was created, and still has access to local variables, even when that function is executed in a different context — or scope.
For example:
function sayHi(name) {var greetingText = "Hi there, ";function speakGreeting(){return greetingText + name;}return speakGreeting()}sayHi('Cass');//=> "Hi there, Cass"
The closure (speakGreeting
) still has access to the outer function’s variables (here, greetingText
) and parameters (here, name
).
Module pattern
Modules help keep our code neatly organized, and optimized for reuse. They also, by making use of closure, allow us to selectively obscure certain details and expose — or make available — selected functionality.
Keeping the concept of closure in mind, we’ll expand our example to reflect a simple implementation of a module.
function sayHi() {var greetingText = "Hi there, ";function speakGreeting(name){return greetingText + name;}function shoutGreeting(name){return greetingText.toUpperCase() + name.toUpperCase();}function sayName(name){return name;}return {speakGreeting: speakGreeting,shoutGreeting: shoutGreeting,sayName: sayName}}var speak = sayHi();speak.speakGreeting('Cass');//=> "Hi there, Cass"speak.shoutGreeting('Dean');//=> "HI THERE, DEAN"speak.sayName('Crowley');//=> "Crowley"
The speakGreeting
and shoutGreeting
functions close over the local variable greetingText
.
After executing the outer function sayHi()
and assigning the returned object to the variable speak
, references to our inner functions speakGreeting
, shoutGreeting
, and sayName
are available as methods on speak
.
What we are doing here is creating an API. Let’s look at a slightly modified example that makes that more clear.
var module = (function outer() {var privateVar = "Hi there, ";function publicFn1(name){return privateVar + name;}function publicFn2(name){return privateVar.toUpperCase() + name.toUpperCase();}function publicFn3(name){return name;}var publicAPI = {publicFn1: publicFn1,publicFn2: publicFn2,publicFn3: publicFn3};return publicAPI;})();module.publicFn1('Cass');//=> "Hi there, Cass"module.publicFn2('Dean');//=> "HI THERE, DEAN"module.publicFn3('Crowley');//=> "Crowley"
What has changed?
- We are immediately invoking our
outer
function and assigning the returned object tomodule
. This is useful when multiple instances aren’t needed - Within the
outer
function, we assign the object we are returning to varpublicAPI
and returnpublicAPI
. This makes clear to anyone reading our code (ourselves included) that we are exposing these methods
The functional result, however, is essentially the same.
Modules are like lego pieces — little units that can be used once, or over and over, depending on what you need and where it’s needed, to build larger, more complex structures — except you can form any piece you need, to your own specifications.
Further reads and sources:
- Closure reads:
- Eloquent JavaScript: Chapter 3: Functions
- JavaScript Is Sexy: Understand JavaScript Closures With Ease
- You Dont Know JS: Scope & Closures
- Module pattern reads:
- You Dont Know JS: Scope & Closures: Modules
- Eloquent JavaScript: Modules
- Addy Osmani: Learning JavaScript Design Patterns