Steviebob Steviebob - 7 months ago 11
Javascript Question

Javascript Module Usage

I'm just getting started with javascript modules and I want to make sure I'm doing it correctly.

Below is an example of the methodology I'm following, based on the "Loose Augmentation Pattern" that I read about here

//myApp.js
var myApp = {};


//someModule1.js
(function (ma) {
ma.someModule1.DoStuff = function () {
alert("hi");
};
return ma;
}(myApp || {}));


//someModule2.js
(function (ma) {
ma.someModule2.DoMoreStuff = function () {
alert("ho");
};
return ma;
}(myApp || {}));


//someModule3.js
myApp.someModule1.DoStuff();
myApp.someModule2.DoMoreStuff();


The myApp variable within myApp.js would be the only variable that's globally exposed, with all of the other modules and their functions only being accessible via this variable.

someModule3.js isn't necessarily a module, but any arbitrary javascript wanting to access the properties of the myApp object (After the appropriate modules have been defined).

The part in particular I'm not 100% clear on is this: (myApp || {}, jQuery)
What is that part called and what exactly is it doing (I know the whole thing is a closure, but I just don't understand exactly how the last part is working)?
It seems like "ma" is initially nothing, I add a function to it in the body of the closure, then return ma. At this point myApp only has the one function.

In the bit at the end (myApp || {}), is it actually saying "ma isn't nothing, it's actually called myApp and I'll append those functions to that object if it exists."

Is that right or am I way off?

Answer

I see four issues:

  1. Your code won't run as is. You have to define .someModule1 before you can assign to it.

  2. There's no reason to do return ma because you aren't using the return value.

  3. There's no reason to pass myApp || {} because if myApp is not defined, then your code will do nothing because the object you created would not be capture in any variable and will just be immediately garbage collected and not be accessible.

  4. As you've shown your code, the IIFE you've enclosed the code in is not accomplishing anything other than adding lines of code and complexity.

Here's more detail on each issue.

Your modules won't run as is. You need to define .someModule1 by changing this and there is no reason in your code to pass myApp || {}:

//someModule1.js
(function (ma) {
    ma.someModule1.DoStuff = function () {
        alert("hi");
    };
    return ma;
}(myApp || {}));

to this:

//someModule1.js
(function (ma) {
    // you must define .someModule1 before you can assign properties to it
    ma.someModule1 = {};
    ma.someModule1.DoStuff = function () {
        alert("hi");
    };
    return ma;
}(myApp));

There is also no reason to do return ma in your code since you are not using the return value.

The reason myApp || {} is of no value here is because if myApp is not defined, then none of the code in your module does anything useful because the underlying object you would be assigning things to is not captured in a variable anywhere. So, if myApp is not defined, then your code accomplishes nothing. So, somewhat by definitino, myApp has to already be defined for your code to be useful, therefore, you can just pass myApp into the IIFE.


As you've shown the code, there is no benefit or reason to putting the assignment of properties inside the IIFE. You don't have any closure variables or anything that is private inside the IIFE. So, you would achieve exactly the same result with this:

myApp.someModule1 = {};
myApp.someModule1.DoStuff = function () {
    alert("hi");
};

There are some reasons for using an IIFE, but you don't show any in this code example. Personally I'm a fan of using the simplest code that achieves your objectives and not adding extra complexity just for sake of it. Other people like to put all their code inside these IIFE modules. I only put my code inside an IIFE when there is actually a reason to have your code in an IIFE.