Search code examples
javascriptmodulethisiife

Why do I need to use an exports / this construction in my IIFE for it to be accessible in Node REPL?


Why does the first version of my javascript code return undefined when I require it in a Node REPL, whereas the second version works?

When I run the two versions of code below in a browser console, they both appear to do what I want (the functions work, var text remains private). This has prompted me to ask why I need to bother with the exports / this construction in the second version.

However I've noticed that the first version (without that construction) doesn't work if I require it in a Node REPL, so clearly exports / this is doing something additional which I don't understand.

Can anyone explain why it is necessary in simple terms (I'm relatively new to JS).

First version without an IIFE and exports/this:

function Note(string) {

  var text = string;

  function getText() {
    return text;
  }

  return {
    getText: getText
  }

}

Second version with an IIFE and exports/this:

(function(exports) {

  function Note(string) {

    var text = string;

    function getText() {
      return text;
    }

    return {
      getText: getText
    }

  }

  exports.Note = Note;

})(this);

Solution

  • You've said you're "requiring" it. When you do that, the code is treated as a Node module. (Node almost always treats your code as a module.) Module code isn't at global scope, it's in a scope specific to your module. That's why you need to export the things from it that you want exported (everything else is private by default).

    In constrast, in a browser, unless you do something on purpose to keep it from being global it's global, so your code without the wrapper and export creates a global Note when run in the global scope.

    In the modules documentation, they show you how your code is run when loaded as a module:

     (function(exports, require, module, __filename, __dirname) {
     // Module code actually lives in here
     });
    

    That's then called such that this is the exports object (this === exports is true), although I don't see that documented anywhere and certainly wouldn't use that fact.