Hide Document Parts:
Images
   Digital Media
Forms
QR Code
Output Options:
Print Document
Download PDF
Article
Comments

The Revealing Module Pattern + A Beginners Mistake

Having presented my Senior Project – Hive Learning Management System – to the powers that be and about to graduate from Brigham Young University Idaho in less than a week, I was less than thrilled to realize I made a major beginners mistake in all of the JavaScript self revealing modules for Hive. In this article I’ll share with you what the revealing module pattern is all about and how you can avoid my annoying and time consuming mistake.

As a precursor to this article, and your going to have to take my word on this since I can’t find the original article, I’m fairly certain I was taught self revealing modules incorrectly from some programmers blog post. He seemed so knowledgeable.

I found it online so it must be true!

All sarcasm aside though when I hit the books again (googled for help) I found Joe Zimmerman’s article JavaScript Closures and the Module Pattern to be extremely helpful. I had read several articles like it before (most three times longer than his) but his short and sweet code examples got me back on track fast. Lets take a look at the mistake I made with implementing the revealing module first:

var NavigationManager = function NavigationManager(){
    iframeInterval = null,
    onHold = new LinkList(),
    display = function(){
    },
    // ... all the other methods here
    return {
        // ... all the methods (functions/ variables) I want to reveal
    }
}();

var NotificationManager= function NotificationManager(){
    defaultId = 'notifications',
    icons = {
        // ... object structure omitted
    }
    display = function(){
    },
    // ... all the other methods here
    return {
        // ... all the methods (functions/ variables) I want to reveal
    }
}();

Can you see what I did wrong? If not that’s ok I’m here to teach you from my mistakes.

What I Did Wrong

Really the only major issue with the above code is I misunderstood scope and by doing so I accidentally started overwriting what should have been private functions. In this example, because of the order their declared, the NotificationManager will overwrite the NavigationManagers display function in certain circumstances. I’m familiar with how scope works in JavaScript so I knew NavigationManger and NotificationManager were going to end up being added to the global scope, but I incorrectly assumed from my teaching (internet research) that everything declared inside them was going to be considered local except for what I choose to expose (return). Even if I had made these revealing modules as true immediately invoked and therefore enclosed functions I would still run into the same problem under the right circumstances. If you have no idea what I mean by that you might want to read Ben Alman’s article on Immediately-Invoked Function Expression (IIFE). Essentially even if my code was written like this:

var NavigationManager = (function NavigationManager(){
    // ... All the good stuff here
})();

The way I declared my methods would still cause them all to be added into the global scope. If you don’t understand what I mean, can’t see how this code is a major issue, or would like to see what I’m saying in action you really should try my little hands on experiment in the next section. Feel free to skip it if your not interested.

An Experiment

Copy the following code into your internet browsers developer console, run it (press enter), and then print all the contents of the window object; just type window and press enter. A window object should print out to your console which you can then open up and view all the JavaScript functions and variables that have been added to the global scope. Near the top you should see the two functions ALittleExampleOne and ALittleExampleTwo but you will only see one ALittleFun function.

var ALittleExampleOne = (function ALittleExampleOne(){
    MyLittleTest = function(){
        ALittleFun();
    },
    ALittleFun = function(){
        console.log('I CAME FROM ONE!');
    };
    return {
        MyLittleTest: MyLittleTest,
        ALittleFun: ALittleFun
    };
})();

var ALittleExampleTwo = (function ALittleExampleTwo(){
    MyLittleTest = function(){
        ALittleFun();
    },
    ALittleFun = function(){
        console.log('I CAME FROM TWO!');
    };
    return {
        MyLittleTest: MyLittleTest,
        ALittleFun: ALittleFun
    };
})();

If you type the following into your developers console or copy paste and run the code you should get two lines printed back to you, one saying “I CAME FROM ONE!” and another saying “I CAME FROM TWO!”.

ALittleExampleOne.ALittleFun();
ALittleExampleTwo.ALittleFun();

It was at this point that I figured all was well and moved on developing other things without realizing that I had a major bug on my hands! Go ahead and run the following line in your developers console so you can see what I mean:

ALittleExampleOne.MyLittleTest();
ALittleExampleTwo.MyLittleTest();

What did you get back this time? You should see the line “I CAME FROM TWO!” printed twice in your developers console or you should see the line once with a number two next to it indicating that the console detected this same output twice. But why did this happen, it was working before in the last example?

The answer is scope. When inside the ALittleExampleOne module everything does start internally as local scope but when I call a function like MyLittleTest that in turn calls another function in the same module a lookup occurs (not the official term). The computer first looks locally and then globally for the function we’re trying to find. In this example everything inside ALittleExampleOne and ALittleExampleTwo was accidentally and unknowingly declared as global so when you call ALittleExampleOne.MyLittleTest it jumps first to the local scope, finds nothings matching, and then jumps to the global scope which does in fact have the MyLittleTest function. The only problem though is it was overwritten by ALittleExampleTwo’s version of the MyLittleTest function.

The only reason ALittleExampleOne.ALittleFun and ALittleExampleTwo.ALittleFun returned the correct output in the first example is because the compiler returned direct references to them as part of the return statement. In plain English the following code is setting the scope correctly for us when we call ALittleExampleOne.ALittleFun and ALittleExampleTwo.ALittleFun but any calling of functions from other functions will lose that scope.

return {
    MyLittleTest: MyLittleTest,
    ALittleFun: ALittleFun
};

So lets take a look at scope in action and get a crash course in what scope is like in JavaScript. This example comes right from Joe Zimmerman’s article JavaScript Closures and the Module Pattern.

var globalvar = 1; // Global Scope
function outer() {
    var outervar = 2; // Scope is within outer()
    function inner() {
        var innervar = 3; // Scope is within inner()
        console.log(globalvar); // => 1
        console.log(outervar); // => 2
        console.log(innervar); // => 3
    }
    console.log(globalvar); // => 1
    console.log(outervar); // => 2
    console.log(innervar); // => Reference Error;
}
console.log(globalvar); // => 1
console.log(outervar); // => Reference Error
console.log(innervar); // => Reference Error

Now that we understand scope your probably asking how do we fix this issue then?

How To Do This Right

The answer is simple, declare my variables and functions correctly! Here is the example code from my experiment fixed and working correctly:

var ALittleExampleOne = (function ALittleExampleOne(){
    var MyLittleTest = function(){
        ALittleFun();
    };
    var ALittleFun = function(){
        console.log('I CAME FROM ONE!');
    };
    return {
        MyLittleTest: MyLittleTest,
        ALittleFun: ALittleFun
    };
})();

var ALittleExampleTwo = (function ALittleExampleTwo(){
    var MyLittleTest = function(){
        ALittleFun();
    };
    var ALittleFun = function(){
        console.log('I CAME FROM TWO!');
    };
    return {
        MyLittleTest: MyLittleTest,
        ALittleFun: ALittleFun
    };
})();

Now if you go back to your console and run the following code you should get back two different outputs, one saying “I CAME FROM ONE!” and another saying “I CAME FROM TWO!”.

ALittleExampleOne.MyLittleTest();
ALittleExampleTwo.MyLittleTest();

Also, if you print out the window object again and look through the functions and variables you should not see an entry for MyLittleTest or ALittleFun. These functions have now correctly been contained and bound inside their respective modules. Now when you happen to use the same namespace (name) for a function in one module you wont accidentally overwrite a function named the same in another module.

Comments are currently disabled. Please check back later.
Close
Categories