JavaScript is a wonderful language to get thinks fundamentally wrong from the start. As so where are many patters around to help us to avoid some of these challenges ;-).
The module pattern is one of the most known and used. It helps us to create private variables or better to avoid side effects in a larger JS application between the different JS files we load or frameworks we use.
The problem
Overall the problem is that in JavaScript everything is more or less public. Currently, most frameworks register their name in the Global space, also known as the window Object. You know them as angular
or just $
or maybe even as Y
.
Imagine the following code (jsBin):
// first JS file var CLASS_NAME = "A1"; function A1() {} A1.prototype.sayHallo = function() { $('#out').html(CLASS_NAME + ": says hallo!"); }; // second class in a different JS file var CLASS_NAME = "B1"; function B1() {} B1.prototype.sayHallo = function() { $('#out').html(CLASS_NAME + ": says hallo!"); }; // some code $('#cmdA1').click(function() { new A1().sayHallo(); }); $('#cmdB1').click(function() { new B1().sayHallo(); });
It doesn’t matter which button you press the result will always be B1
because we have overwritten the value in CLASS_NAME
in the second part.
Even if this sample is somehow of course constructed, this problem can easily happen in a larger JS application. We must take this into account an protect ourself.
The solution
The solution is pretty straight forward. We just wrap our class definition into an anonymous function. This does not only protect us but it allows us to create really private variables in JS which can’t be overwritten from outside — we can protect the access to them with functions.
// first JS file MyGlobal = {}; (function($) { var CLASS_NAME = "A1"; function A1() {} A1.prototype.sayHallo = function() { $('#out').html(CLASS_NAME + ": says hallo!"); }; MyGlobal.A1 = A1; })(window.$); // pass any global scope // second class in a different JS file (function($) { var CLASS_NAME = "B1"; function B1() {} B1.prototype.sayHallo = function() { $('#out').html(CLASS_NAME + ": says hallo!"); }; MyGlobal.B1 = B1; })(window.$); // some code $('#cmdA1').click(function() { new MyGlobal.A1().sayHallo(); }); $('#cmdB1').click(function() { new MyGlobal.B1().sayHallo(); });
What have we learned?
- In JavaScript, the best practice is to wrap our code into anonymous functions
- Define one global scope variable which we use to register all our classes (here MyGlobal)
- Anonymous function also allow us to create private/ protected variables