Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript

Ignacio Martin Elias
Ignacio Martin Elias
10,127 Points

I don't understand the Module Pattern... Please Help!

I tried reading the questions and answers to this video, but it's still a bit complicated to understand to me.

I don't know how would this "mechanic" work...

!(function(something){ something.dothis = function(){ blablabla; } })(something);

Does this means I'm adding the .dothis() functionality to my "something"?

How does exactly the "export" keyword works? On what type of object do I use it? When do I use it?

I'm so confused....

2 Answers

Brendan Whiting
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Brendan Whiting
Front End Web Development Techdegree Graduate 84,735 Points

Let me take a step back from this for a minute and make sure we're on the same page with functions. We can define functions with a name, or we can defined anonymous functions:

function namedFunction() {
    console.log(this has a name);
}

function() {
    console.log(this is anonymous);
}

Later on, we could call the function namedFunction(), but the anonymous one we have no way of calling somewhere else in the code. Usually, anonymous functions are used in callbacks, since we can just define this function in place, and this is the only place it’s going to be used.

button.addEventListener("click", function(){ 
    console.log(this is anonymous);
});

But another use of the anonymous function is in this module pattern, something called an an IIFE (pronounce “iffy”) - Immediately Invoked Function Expression. The function itself is wrapped in parens so that it will be treated as a function expression as opposed to a function declaration (don’t worry about that part too much right now), and then this function is immediately called with parens.

(function() {
    var message = Hello World);
    console.log(message);
})()

This is almost the same as if we’d ran the same code, but not wrapped in an IIFE:

var message = Hello World);
console.log(message);

But in the first case, the variable message will not exist in the global scope, but in the second case it will be. If we’re concerned about polluting the global namespace, this can solve that problem.

Now in this case:

!(function(something){ 
    something.dothis = function(){ 
        // blablabla; 
    } 
})(something);

Here the assumption is that there is a variable called something that already exists in the global namespace at the time this is run. The anonymous function inside the IIFE takes one parameter - called something. When we immediately invoke it, we pass in the argument something which is already there in the global scope. In the example in the video, they passed in _ which would be the variable holding everything from the lodash/underscore library (there's probably a script tag on the page that imports this library before this JavaScript code is run).

Inside the anonymous function in the IIFE, it takes that existing variable and it adds a new property to it, in this case a method called doThis. Now that method will be available on the variable something along with everything else the was there previously. In the example in the video, it would be like you were using the lodash library but you had your own custom utility function that you wanted to add in to the mix when you use that library in your code.


It’s important for me to point out that the module pattern in this video is out of date, and it’s much cleaner to use modern ES6 modules and a module bundler like webpack. If you’re using create-react-app you’ll get the module bundling from webpack automatically behind the scenes.

In the example in the video, exports isn't a special keyword, it's just an object that we return from the inner anonymous function that contains everything we want it to return and make available in the global scope. In the new ES6 modules, export is a special keyword it works a bit differently. You might have got mixed up by looking at both the older and newer versions of JavaScript modules.

Ignacio Martin Elias
Ignacio Martin Elias
10,127 Points

Thank you so much, this helped me a lot! I understood it perfectly! Yes, I mixed up the export special keyword with the export object... Also I think the posible syntax for the IIFE are 3, kind of confusing as well. But I think I got it right.

(function(){})() 
+function(){}()
!function(){}()
Brendan Whiting
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Brendan Whiting
Front End Web Development Techdegree Graduate 84,735 Points

I just looked at the code that is generated by webpack, and it's actually an IIFE starting with an exclamation point. Interesting! But you also don't have to touch this file it's just generated by the tool. (This is a program that just console.logs "hello world").

! function(e) {
    var t = {};

    function r(n) {
        if (t[n]) return t[n].exports;
        var o = t[n] = {
            i: n,
            l: !1,
            exports: {}
        };
        return e[n].call(o.exports, o, o.exports, r), o.l = !0, o.exports
    }
    r.m = e, r.c = t, r.d = function(e, t, n) {
        r.o(e, t) || Object.defineProperty(e, t, {
            enumerable: !0,
            get: n
        })
    }, r.r = function(e) {
        "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, {
            value: "Module"
        }), Object.defineProperty(e, "__esModule", {
            value: !0
        })
    }, r.t = function(e, t) {
        if (1 & t && (e = r(e)), 8 & t) return e;
        if (4 & t && "object" == typeof e && e && e.__esModule) return e;
        var n = Object.create(null);
        if (r.r(n), Object.defineProperty(n, "default", {
                enumerable: !0,
                value: e
            }), 2 & t && "string" != typeof e)
            for (var o in e) r.d(n, o, function(t) {
                return e[t]
            }.bind(null, o));
        return n
    }, r.n = function(e) {
        var t = e && e.__esModule ? function() {
            return e.default
        } : function() {
            return e
        };
        return r.d(t, "a", t), t
    }, r.o = function(e, t) {
        return Object.prototype.hasOwnProperty.call(e, t)
    }, r.p = "", r(r.s = 0)
}([function(e, t, r) {
    "use strict";
    r.r(t);
    console.log("Hello world")
}]);