DEV Community

Module pattern in JavaScript

Tomasz Buszewski on February 26, 2019

A module is a construct somewhat similar to a singleton class. It has only one instance and exposes its members, but it doesn’t have any kind of in...
Collapse
 
bayazz profile image
Bayazz

You said with Formatter.timesRun = 10; We access timesRun variable and change it. But actually when we call makeUpperCase method we see that timesRun is still 0 and it doesn't change. Could you please explain this strange behavior?

Collapse
 
yufan029 profile image
Yufan029 • Edited

This is because the F.timesRun, and the IIFE's timesRun (which means the timesRun that inner function modified) are different things.

code sample:

const F = (function() {
    let timesRun = 0;

    function getTimesRun() {
      console.log(timesRun);
    }

    function plusTimesRun() {
        timesRun++;
    }

    return {
        timesRun,
        getTimesRun,
        plusTimesRun
    };
})();

F.getTimesRun();

F.plusTimesRun();
F.plusTimesRun();

F.getTimesRun();

console.log(F.timesRun);
F.timesRun += 10;
console.log(F.timesRun);
Enter fullscreen mode Exit fullscreen mode

When the IIFE run, the new object created which is

{
    timesRun, 
    getTimesRun,
    plusTimesRun
}
Enter fullscreen mode Exit fullscreen mode

This is F, new created object, since 'timesRun' is a primitive value, it is copied by value.

After it's being created the 'timesRun' in the new created object is no relationship with the 'timesRun' in IIFE.

Inside this new created returne object, 'timesRun' got the value copied from the IIFE when IIFE run.

At the same time, the 'getTimesRun' and 'plusTimesRun' also remember a different 'timesRun' by closure, which is the original 'timesRun' in the IIFE, and is different from the 'timesRun' property of the new created object.

So, when you change the F.timesRun, only this property changed.

When you run plusTimesRun, the closure timesRun changed, two different properties, this timesRun is remembered via closure by plusTimesRun.

You can totally modify the return sentence like:

return {
     newTimesRun: timesRun,
     getTimesRun, 
     plusTimesRun
}
Enter fullscreen mode Exit fullscreen mode

Then use F.newTimesRun = 10; to change the new created property.
And change the closure 'timesRun' via 'plusTimesRun'.

Hope I made this clear.

Collapse
 
tomekbuszewski profile image
Tomasz Buszewski

Hi Bayazz!

Can you reproduce the problem or show the code? I did run the one from example on codesandbox and it seems fine.

Collapse
 
central profile image
Sumukha Pawar

Old post, but I'll share my solution: The reason you're always seeing 0 for timesRun is due to the closure behavior. When you call Formatter.makeUppercase(), it increments timesRun, but the closure keeps the reference to the original timesRun within the IIFE. So, calls made to the Formatter.timesRun will be the initial value 0.
To fix this, you should modify your code slightly. Instead of directly returning timeRun as a property of the Formatter object, return a function that retrieves the current value of timesRun. This way, the closure will keep a reference to the function, and it will always reflect the updated value.

Collapse
 
bayazz profile image
Bayazz • Edited

Hi Tomek,
thanks for the reply.

If we add console.log(timesRun);in the setTimesRun method right after ++timesRun; we can see in the console that timesRun is not 10. But with Formatter.timesRun it's 10.

codesandbox.io/s/lingering-sound-g...

Collapse
 
bayazz profile image
Bayazz

Any ideas? Im still struggling to understand it.
Thanks

Collapse
 
m0xai profile image
m0xai

A little thing:
Before running the code in Exposing a Module, you deleted the line " console.log("Start");" i mean, we can't see this console.log just before invoking the function. But in output you added it in first line.

Collapse
 
taf profile image
taff

great explanation. I don't know if this is obsolete anymore but I'm learning one at a time. thank you.

Collapse
 
guico33 profile image
guico33

Now we have actual modules with esm or even commonjs, what's the point of creating modules using an IIFE?
To me it sounds like a pattern which should disappear in favor of more modern practices.

Collapse
 
tomekbuszewski profile image
Tomasz Buszewski

Hi Guico,
You are right about the new modular approaches, I just might be a little late to the party with this article ;)

Nevertheless, I still find IIFE often in codebases I work with while doing consulting or audit stuff. And I don't think those are for refactor (even though it would be quite painless), as such modules are valid and fully functional parts of an application.

Collapse
 
lizsafina profile image
LizSafina

Hey, great article. Thank you!
Just one thing:
I even removed the check inside makeUppercase, because it’s not needed anymore
Did you mean "you removed the check inside 'writeToDom'?"

Collapse
 
hareom284 profile image
Harry • Edited

Thank man this article

Collapse
 
er_carltz_ad2c0e2e57f54b3 profile image
ER Carltz

This is WILD

Collapse
 
axterix profile image
Axterix

Thanks for your post, clear a nice explained.... was very usefull and informative.