JavaScript Design Patterns Help Needed: Loose Augmentation of Modules
Asked Answered
I

3

8

Edit for clarity - @Qantas94Heavy - I understand what it is "saying" or supposed to do, what I don't understand is why & more importantly how it works:

I was reading an advanced tutorial on the JS Module Pattern, and it gave this example:

var MODULE = (function (my) {
// add capabilities...

return my;
}(MODULE || {}));

The thing that is bugging me (and I need your help with) is the last statement:

(MODULE || {}));

i'm having trouble understanding the syntax rules behind this that make it possible. After doing some searching for keywords, "JavaScript Module Syntax", and "Module Pattern Short Hand" I found that I'm still not quite understanding the foundation behind this.

Would someone please explain or point me in the right direction for grokking this/gaining a deeper understanding?

Sincerely, gggi

Impalpable answered 24/8, 2013 at 17:3 Comment(4)
It's either passing an already-defined part of the module or if it doesn't exist, creating a new object for the module - the function is called immediately, passing the result of the function to the assignment.Venus
@Qantas94Heavy Why not write it as an answer instead of a comment?Illuminant
@Qantas94Heavy - I understand what it is "saying" or supposed to do, what I don't understand is why & more importantly how it works.Impalpable
@Bart: way past the onset of tiredness, not enough time to substantiate an answer.Venus
S
7
(function(){

})();

is a self-invoking anonymous function. In your case, it handles the "my" object parameter: it does something to "my" and then returns it back.

In your case the "my" parameter the function receives is "(MODULE || {})".

The && and || operators are called short-circuit operators. || will return, if "MODULE" object exists, the "MODULE" object, otherwise, an empty object will be created to be used inside the function. The function will do whatever it does to that object, which will became the returned "MODULE" object.

It works by creating a closure: as long as MODULE exists (it's not garbage collected) so does the self-invoking anonymous function along with its state at the time of assignment. This makes any capabilities added to be persistent.

Sizzle answered 24/8, 2013 at 17:36 Comment(1)
Thank you @itmitică - I guess the way that this was explained to me lead me to believe there was something more going on here than the simple shorthand if determining what's passed in! In retrospect this is quite simple.Impalpable
S
3

The right-hand-side is called immediate function. To understand how it works, let's break it down a bit:

  1. (...)() we can call a function by name, i.e. f(). But, instead of function name, we can place any expression that resolves to a variable of type function. In our case, the first set of parenthesis merely encloses an expression. The second set is function call operator. Ultimately, (f)() is equivalent exactly to f()

  2. The second step is to provide an anonymous function inside the first parenthesis set. The result is: (function(){})(). The anonymous function is perfectly of type function. This causes the function to be created, executed and discarded all in the same statement.

  3. The second set of parenthesis which is the function call operator can accept parameters inside it, which is in our case MODULE || {}. This expression means: if MODULE is defined, use it, otherwise, create a new empty one.

  4. The parameter is passed to the anonymous function as an argument called my and the anonymous function returns, um, my. This causes the anonymous function to evaluate to my and in effect: (my)(MODULE || {}).

  5. The effect is MODULE is self contained and causes no name clashes with outside variables. While, in the same time, it has access to outside variables.

I hope this clears it :)

Sutra answered 24/8, 2013 at 18:11 Comment(0)
C
0

rarely, especially for large projects we’re gonna to have all our code in one file, at first it’s easy enough to put your code in different files and smash them together in a specific order, however this quickly becomes unmanageable, using unknown pattern called “lose augmentation” we can actually take advantage of javascript asynchronous runtime environment.

to implement this pattern we are gonna a small piece of logic. We’re gonna say if awesomeNewModule exist, then imported it, otherwise awesomeNewModule is simply new object:

    var awesomeNewModule = (function(){
        var exports={
            foo:5,
            bar:10
        };
        exports.helloMars = function(){
            console.log("Hello Mars!");
        };
        exports.goodbye = function(){
            console.log("Goodbye!");
        }
        return exports;
    }(awesomeNewModule || {}));

and up here since we’re using exports keyword, we’re gonna say that awesomeNewModule is exports within a function, now all these values of exports {foo:5, bar:10} will either get assigned to the empty object {} if this was the first file or will get assigned and extend awesomeNewModule if this file was loaded after the module had already been created.

var awesomeNewModule = (function(exports){
    var exports={
        foo:5,
        bar:10
    };
    exports.helloMars = function(){
        console.log("Hello Mars!");
    };
    exports.goodbye = function(){
        console.log("Goodbye!");
    }
    return exports;
}(awesomeNewModule || {}));

one of the important thing to keep in mind is that if awesomeNewModule is already exist, then you should make sure that none of these keys {foo:5, bar:10} already exist in awesomeNewModule as well none of these methods: exports.helloMars , exports.goodbye if so, whatever file is loaded last will override any methods or values that were named the same in previous files.

for this reason you can’t share values across the modules, if any aspect of one module depends on another then you can’t safe we depend on those values, but at the end of the day the whole point of writing module or code is that you split your app in pieces that don’t depend on each other, this way if one module introduces a breaking error to the application, doesn’t affect the rush of the code. Additionally there are ways to safe cards to make sure that one module doesn’t override patterns or methods created from another modules.

source: treehouse workshop about basics of Module Pattern in javascript
Carlitacarlo answered 27/3, 2020 at 19:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.