Search code examples
javascriptmoduleiife

Difference between an IIFE and non-IIFE in JavaScript Modular approach


Recently while I was trying to learn more about IIFE and modules in JavaScript a question came to my mind that how is IIFE making a Module while not Immediately Invoking the function doesn't make it a module..

can anyone share with me the Difference between this code

var MODULE = (function () {
var my = {},
    privateVariable = 1;

function privateMethod() {
    // ...
}

my.moduleProperty = 1;
my.moduleMethod = function () {
    // ...
};

return my;
}());

and this code where the function is not Immediately Invoked..

var MODULE = function () {
var my = {},
    privateVariable = 1;

function privateMethod() {
    // ...
}

my.moduleProperty = 1;
my.moduleMethod = function () {
    // ...
};

return my;
};

Does the second block of code means that Module is just a function that itself returns an object?

IF I use the second variable like this

var ModuleObj = Module();

Will this work the same as the first Code block that I shared like IIFE.. Kind of confused...


Solution

  • Yeah you pretty much got the idea of the difference between the two, let's look at why you might want one over the other.

    An IIFE is useful to isolate the scope. It lets you keep the variables you define private inside the IIFE without polluting the global space around it. It's a nice way to compose a function that has some variables you don't need lurking around. Let's minimize this example a bit.

    var Counter = (function () {
      var count = 0;
    
      var counter = {
        add: function () {
          count++;
        },
        subtract: function () {
          count--;
        },
        getCount: function () {
          return count;
        }
      }
      return counter;
    })();
    
    Counter.add();
    Counter.add();
    Counter.getCount(); // 2
    Counter.subtract();
    Counter.getCount(); // 1
    

    What happens above is that we're able to compose this "counter" functionality without leaking the private information, like count. It'd be bad if other things could override it by accident. Also what happens is that right away we can assign Counter to the result of the IFFE -- the counter set of functions. Counter is now equal to that, and counter is able to retain access to count since it was defined in the same scope.

    The benefit here is that we're able to assign a variable to this composition of functionality. The IIFE basically allows us to immediately return what we return inside of it. Since we assign Counter to the IIFE, and the IIFE returns the functionality inside of it, Counter is now a fully functional component.

    We don't always have to use IIFE. It's really handy when you want to "tuck away" the implementation details and return an API.


    So, what if we had the same thing, but it wasn't an IIFE -- just a function?

    Just like your example, we'd have to call it in order to get the "instance".

    var CounterFactory = function () {
      var count = 0;
      var counter = {
        add: //...
        subtract: //...
        getCount: //...
      };
      return counter;
    };
    
    var CounterA = CounterFactory();
    var CounterB = CounterFactory();
    
    CounterA.add();
    CounterA.add();
    CounterA.getCount(); // 2
    
    CounterB.add();
    CounterB.getCount(); // 1
    

    See the difference? It's all about what the function is returning. In the first example we only get a single Counter instance, which may be perfectly fine. In the second example, it's more of a "factory" -- it generates an instance of counter and we can call that multiple times and get multiple instances of it.