Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
145 lines (118 sloc) 5.33 KB
<!DOCTYPE html>
<html>
<!--
An exploration of the Module Pattern, a useful method for encapsulation in
JavaScript.
If you want to learn more about JavaScript and "the right way" to write it,
read The Good Parts, by Douglas Crockford. I can't recommend it enough.
http://shop.oreilly.com/product/9780596517748.do
Note that this is NOT the only way to implement the Module Pattern. It is,
however, my favorite way. I prefer it because it's simple to implement,
easy to read, and avoids a lot of the JavaScript-specific concepts that
trip up developers unfamiliar with the language.
Enjoy!
Author:
Steve Kwan
mail@stevekwan.com
http://www.stevekwan.com/
Originally from my GitHub:
https://github.com/stevekwan/experiments/
Date: Feb 21, 2013
-->
<head>
</head>
<body>
<script>
// The module pattern is a good way to encapsulate your JavaScript functions
// and properties. The example below shows how to create a module, namespace
// it, and specify public/private properties and functions.
// Be aware that the Module Pattern is NOT generally used for object-oriented
// programming. It does not give you the ability to define a class that can
// spawn objects based on its definition. Although it is possible to jerry
// rig the Module Pattern to define classes, there isn't a real benefit to
// doing this as JavaScript has another facility for this.
// If you are more interested in laying out a classical object-oriented
// hierarchy, look at this example instead:
// https://github.com/stevekwan/experiments/blob/master/javascript/class.html
// However, be aware that JavaScript is not a classically object-oriented
// language. If you are trying to write true classical OOP in JavaScript,
// you're probably doing it wrong. :)
// Advantages of the Module Pattern:
// -Avoids nonsense with the "this" keyword, which often causes confusion
// -Gives you basic encapsulation without having to write a lot of code
// -If you are creating a singleton "class," the Module Pattern is for you.
// Disadvantages of the Module Pattern:
// -True class-based OOP doesn't work well with the Module Pattern.
// First, let's create a namespace. It's not required, but it's usually a
// good idea.
var MyNamespace = MyNamespace || {};
// Let's add our module to the namespace. Basically, it's just a property of
// the namespace. Note that our module is actually a function. We're going
// to use JavaScript closures to emulate private methods, which are not
// natively part of JavaScript.
MyNamespace.MyModule = function()
{
// Let's define a private and public property. Note that we define them in
// exactly the same way. The bit that specifies whether they are
// public/private comes later...
var myPrivateProperty = 2;
var myPublicProperty = 1;
// Let's declare a simple private function.
var myPrivateFunction = function()
{
console.log("myPrivateFunction()");
};
// Now let's declare a public function. Again, note that the function
// definition is exactly the same as the private one.
var myPublicFunction = function()
{
console.log("myPublicFunction()");
// Just for fun, let's call our private function. Note that while we are
// inside the module, we have full access to all Module properties and
// functions, just like if we were inside a class.
myPrivateFunction();
};
// Let's make a setup function for this module: something that is called
// once when it's loaded. I generally like to call my setup functions
// init().
var init = function()
{
// Do some setup stuff
console.log("init()");
};
// This is the part that separates the private and public stuff. Anything
// in this object becomes public. Anything NOT in this object becomes
// private.
var oPublic =
{
init: init,
myPublicProperty: myPublicProperty,
myPublicFunction: myPublicFunction
};
return oPublic;
}();
// This is the interesting part: we are returning our oPublic interface, and
// immediately invoking our MyModule function with the () at the end.
// We do this because we are not actually saving the function we created; we
// are saving the RESULT of the function. The () makes us immediately call
// the function, and it is the result we save. The original function itself
// is discarded...but its contents live on via JavaScript closures!
// MyModule is not the function we have defined; rather, it is the result of
// an anonymous function that was called once and discarded. Because that
// function doesn't have a name, we can't refer to its internal properties
// directly. And that's why the properties NOT in the oPublic interface
// become private. :)
// Let's call our setup function....
console.log("Calling init()...");
MyNamespace.MyModule.init();
// And our public function. Internally, this will call myPrivateFunction.
// This wil work because it's being called from inside the module.
console.log("Calling myPublicFunction()...");
MyNamespace.MyModule.myPublicFunction();
// This will throw an error because myPrivateFunction() is not accessible
// from outside the module.
console.log("Calling myPrivateFunction()...");
MyNamespace.MyModule.myPrivateFunction();
</script>
</body>
</html>