JavaScript design pattern: difference between module pattern and revealing module pattern?
There are at least three different ways to implement the Module Pattern, but the Revealing Module Pattern is the only Module Pattern descendant that has an official name.
The Basic Module Pattern
The Module Pattern must satisfy the following:
- Private members live in the closure.
- Public members are exposed in the return object.
But there's a lot of ambiguity in this definition. By resolving the ambiguity differently, you get variants of the Module Pattern.
The Revealing Module Pattern
The Revealing Module Pattern is the most famous and most popular of the Module Pattern variants. It has a number of advantages over the other alternatives, such as
- Rename public functions without changing function body.
- Change members from public to private or vice versa by modifying a single line, without changing the function body.
The RMP satisfies three additional conditions in addition to those in the original:
- All members, whether public or private, are defined in the closure.
- The return object is an object literal with no function definitions. All right hand side expressions are closure variables
- All references are via the closure variables, not the return object.
The following example shows how it's used
var welcomeModule = (function(){
var name = "John";
var hello = function(){ console.log("Hello, " + name + "!");}
var welcome = function() { console.log( hello() + " Welcome to StackOverflow!");}
return {
name: name,
sayHello: hello,
sayWelcome: welcome
}
})();
If you wanted to make name
and sayHello
private, you just need to comment out the appropriate lines in the return object.
var welcomeModule = (function(){
var name = "John";
var hello = function(){ console.log("Hello, " + name + "!");}
var welcome = function() { console.log( hello() + " Welcome to StackOverflow!");}
return {
//name: name,
//sayHello: hello,
sayWelcome: welcome
}
})();
The Module Pattern with Object Literal
This is probably the oldest variant of the Module Pattern. Unlike RMP, there's no sexy official name for this variant.
It satisfies the following conditions, in addition to the original:
- Private members are defined in the closure.
- Public members are defined in the return object literal.
- References to public members are via
this
, whenever possible.
In the following example, you can see how, in contrast to RMP, the function definitions are actually in the return object literal, and references to members are qualified by this
.
var welcomeModule = (function(){
return {
name: "John",
sayHello: function(){ console.log("Hello, " + this.name + "!");}
sayWelcome: function() { console.log( this.hello() + " Welcome to StackOverflow!");}
}
})();
Note that unlike RMP, in order to make name
and sayHello
private, the references pointing to name
and sayHello
in the various function body definitions also have to be changed.
var welcomeModule = (function(){
var name = "John";
var sayHello = function(){ console.log("Hello, " + name + "!");};
return {
//name: "John",
//sayHello: function(){ console.log("Hello, " + this.name + "!");}
sayWelcome: function() { console.log( hello() + " Welcome to StackOverflow!");}
}
})();
The Module Pattern with Return Object Stub
This variant also has no official name.
It satisfies the following conditions, in addition to the original:
- An empty return object stub is defined at the beginning.
- Private members are defined in the closure.
- Public members are defined as members of the stub
- References to public members are via the stub object
Using our old example, you can see that public members are directly added to the stub object.
var welcomeModule = (function(){
var stub = {};
stub.name = "John";
stub.sayHello = function(){ console.log("Hello, " + stub.name + "!");}
stub.sayWelcome = function() { console.log( stub.hello() + " Welcome to StackOverflow!");}
return stub;
})();
If you want to make name
and sayHello
private as before, the references to the now-private members have to be changed.
var welcomeModule = (function(){
var stub = {};
var name = "John";
var sayHello = function(){ console.log("Hello, " + name + "!");}
stub.sayWelcome = function() { console.log( hello() + " Welcome to StackOverflow!");}
return stub;
})();
Summary
The differences between the Revealing Module Pattern and the other variants of the Module Pattern is primarily in how public members are referenced. As a result, RMP is much easier to use and modify, which accounts for its popularity. However, these advantages come at a great cost (in my opinion), which Addy Osmani alludes to in his post on the Revealing Module Pattern,
A disadvantage of this pattern is that if a private function refers to a public function, that public function can't be overridden if a patch is necessary. This is because the private function will continue to refer to the private implementation and the pattern doesn't apply to public members, only to functions.
Public object members which refer to private variables are also subject to the no-patch rule notes above.
As a result of this, modules created with the Revealing Module pattern may be more fragile than those created with the original Module pattern, so care should be taken during usage.
and which I've talked about in some other posts.
Difference between Revealing Module Pattern and simple Constructor
In your simple example there is no difference, but let me make it just a little more complicated.
var moduleRevealing = function() { var talk = function() { console.log("Talking...."); }; var walk = function() { console.log("Walking..."); }; var walkAndTalk = function(){ walk(); talk(); }; return { talk: talk, walk: walk, walkAndTalk: walkAndTalk } };
Are the module pattern and revealing module pattern in Javascript only useful when creating API's?
The module/revealing module patterns are used for encapsulation. The very concept of encapsulating your implementation details means that you're choosing to expose a specific API, to make working with the module simpler.
Constructors are nice if you can leverage javascript's prototypal inheritance, which will allow your instances to "reuse" prototype methods.
As a note:
You seem to say that creating APIs is a rare event in software development. I'd argue you're almost always creating some form of API, because that's how different parts of your application will be interacting with one another: through their APIs. Knowing only the API, and ignoring the implementation details of each module, will greatly simplify maintenance of your code base.
Difference between using a module pattern and instantiating new objects
The key difference between the two is in the first example, you can't have private variables and functions if you want to work with the prototype. You can have private variables and functions, but only if your public properties and methods are created in the constructor by attaching them to this
.
Example 1 with a private variable and function:
var Foo = function(){
var privateVar = "priv";
function privateFunction(){
console.log(privateVar);
}
this.publicProperty = 1;
this.publicFunction = function(){
console.log(privateVar);
}
}
The above is no problem if you don't want to use the prototype. However, if you do then there is no way to have private variables, without the new scope that your second example benefits from.
As you can see, you have to include everything within the constructor, whereas the second example you can leave the constructor just for initialising variables.
Conversely, the prototype methods in the second example are out of scope of the constructor, so they can't use any variables of functions within the constructor. All functions and variables that the prototype methods need must be declared in the outer closure scope.
Javascript 'normal' objects vs module pattern
If you're only going to be using one instance per page, I don't see the need to involve the new
keyword. So personally I would create a revealing module like you did in your last example, and expose an object with the "public" properties.
Though I don't see your point with the getModel()
function, since MyModel
is obviously accessable outside of the scope.
I would have rewritten it slightly:
var LoginModel = (function(model, window, undefined){
function init(){ } // or whatever
function doSomethingWithModel(){
console.log(model);
}
return { init: init };
})(MyModel, window);
If you're uncertain of which modules that will get a model
, you can use loose augumentation and change
})(MyModel, window);
to
})(MyModel || {}, window);
If you need several instances of a module, it would look something like this:
var LoginModel = (function(model, window, undefined){
function loginModel(name){ // constructor
this.name = name; // something instance specific
}
loginModel.prototype.getName = function(){
return this.name;
};
return loginModel;
})(MyModel, window);
var lm1 = new LoginModel('foo');
var lm2 = new LoginModel('bar');
console.log(lm1.getName(), lm2.getName()); // 'foo', 'bar'
The Revealing Module Pattern (RMP) disadvantages
I read the article that @nemesv referenced me to (Thanks :)) and I thinks there is one more disadvantage that was not mentioned, so I thought I'd add it here for reference. Here is a quote from the article:
Disadvantages
A disadvantage of this pattern is that if a private function refers to
a public function, that public function can't be overridden if a patch
is necessary. This is because the private function will continue to
refer to the private implementation and the pattern doesn't apply to
public members, only to functions.Public object members which refer to private variables are also
subject to the no-patch rule notes above.As a result of this, modules created with the Revealing Module pattern
may be more fragile than those created with the original Module
pattern, so care should be taken during usage.
And my addition:
You can't use inheritance with this pattern. For example:
var Obj = function(){
//do some constructor stuff
}
var InheritingObj = function(){
//do some constructor stuff
}
InheritingObj.prototype = new Obj();
InheritingObj.prototype.constructor = InheritingObj;
This a simple example for inheritance in js, but when using the Revealing Prototype Pattern (archived here) you'll need to do this:
InheritingObj.prototype = (function(){
//some prototype stuff here
}());
which will override you inheritance.
Related Topics
How to Display Binary Data as Image - Extjs 4
What's the Yield Keyword in JavaScript
Where Would I Use a Bitwise Operator in JavaScript
Replace a String in a File with Nodejs
In Bootstrap Open Enlarge Image in Modal
How to Replace a Regex Substring Match in JavaScript
What Does Document.Domain = Document.Domain Do
Google Chromecast Sender Error If Chromecast Extension Is Not Installed or Using Incognito
JavaScript New Date Ordinal (St, Nd, Rd, Th)
Change Route Params Without Reloading in Angular 2
Why Are Certain Function Calls Termed "Illegal Invocations" in JavaScript
How to Call a Parent Method from Child Class in JavaScript
How to Beautify JavaScript Code Using Command Line
ASP.NET MVC 3 Razor: Include JavaScript File in the Head Tag
Angularjs Toggle Class Using Ng-Class
How to Set a Cookie with Expire Time
How to Access Object Property with Invalid Characters
Jquery .Find() Doesn't Return Data in Ie But Does in Firefox and Chrome