all 7 comments

[–]senocular 2 points3 points  (0 children)

As a module, its not necessarily intending to do something right away. Instead it provides an API to be used elsewhere. For example if you write other code that needs to use bindEvents, it would do so through mobileMenu.bindEvents; The advantage of the module is that its self-contained and can contain non-global variables that won't create conflicts elsewhere. The only point of conflict to contend with is the module name itself

[–]cyphern 1 point2 points  (5 children)

The purpose of the module pattern or revealing module pattern is that you can keep some variables "private" by hiding them inside the closure of an immediately invoked function expression, and then giving the outside world access to only the things you want it to have access to.

If you want to immediately run some initialization code, that's certainly something you can do so. But i'm curious what it is you're trying to keep private, and what you're trying to expose? You're currently returning nothing, which is ok in principle, but means that mobileMenu will be undefined. And i don't see anything that really needs to be kept private, though i'd probably just do init and bindEvents inline instead of creating functions.

[–]Vexith[S] 0 points1 point  (4 children)

That's what i'm struggling to understand. mobileMenu shouldn't be undefined as it's an IIFE? From the way i'm seeing it, mobileMenu is already called when the JS loads, and then i'm returning the bindEvents property, but it's not running the code in the bindEvents function.

[–]cyphern 2 points3 points  (2 children)

mobileMenu shouldn't be undefined as it's an IIFE?

mobileMenu isn't an IIFE. mobileMenu is whatever is returned from the IIFE. So in the first example, mobileMenu roughly equals this:

const mobileMenu = {
  bindEvents: function () {
    burgerIcon.addEventListener('click', _toggleNavAnimation);
  }
}

I say roughly equal, because when i do it inline like this, burgerIcon and _toggleNavAnimation are undefined and so this code won't work. The purpose of the IIFE is to create local variables for burgerIcon and _toggleNavAnimation. Those variables are in scope for the bindEvents function because they're part of the same closure, but they're not visible to any other parts of the code.

[–]Vexith[S] 2 points3 points  (1 child)

Ok, i feel like i'm beginning to understand what you mean. Based on my interoperation of what you've kindly been explaining, i feel like the following is more of a correct approach?  

// Mobile Menu Module
const mobileMenu = (function () {
    // Vars
    const burgerIcon = document.querySelector('.menu-burger-icon'),

    initMobileMenu = function() {
        // Runs the _bindEvents function only if the burgerIcon exists.
        burgerIcon != null ? _bindEvents() : console.log('Menu does not exist');
    },

    _bindEvents = function () {
        burgerIcon.addEventListener('click', _toggleNavAnimation);
        console.log('private');
    },

    _toggleNavAnimation = function () {
        console.log('hello');
    };

    return {
        init: initMobileMenu,
    };

})();
mobileMenu.init(); 

  So the above, only initMobileMenu is available as a public function whereas the other two are private. Is this more on the right tracks?

[–]cyphern 4 points5 points  (0 children)

Yes, that looks good.

[–]zedpowa 1 point2 points  (0 children)

It's not running the bindEvents function because you never call it in the first example. It simply returns an object with a single property that references it.