Search code examples
javascriptthisiifestrict-mode

Why write a non-strict-mode IIFE that invokes a strict-mode function expression passed to it?


CodeMirror.net uses this construct (I'm simplifying slightly) to introduce the code for its JavaScript editor:

(function (mod) {
  this.CodeMirror = mod();
})(function () {
  "use strict";
   /* 15,000-odd lines of advanced JS */
})

Now, I understand that this is an IIFE, and I've read a number of posts about them. I understand that, in practice, this code is creating a CodeMirror object. I just don't understand the mechanics.

  1. What is the role of the parameter mod? More broadly, what does it mean when you give a parameter to an IIFE?
  2. What is the role of the inner function expression? It appears that this is related to mod in some way?

Thanks for your help.


Solution

  • In your code:

    (function(mod) {
        this.CodeMirror = mod();
    })(function() {
      "use strict";
       (15,000-odd lines of advanced JS)
    }
    

    mod is the formal parameter to the immediately-invoked function. It's as if the function were declared in a more straightforward way:

    function something(mod) {
        this.CodeMirror = mod();
    }
    

    That function clearly expects that the mod parameter will be a reference to some other function, because the only thing it does is make a function call with it.

    The immediately-invoked function is, in fact, called with a function as the value of the mod parameter: specifically, this one:

    function() {
      "use strict";
       (15,000-odd lines of advanced JS)
    }
    

    That function does whatever it does, and (presumably) returns an object reference to be used as the global CodeMirror entry point.

    Because the first function — the immediately-invoked one — is invoked without any explicit this value, it expects that this will be set to the value of the global context, or window in a browser. Personally I think it would be safer to do that explicitly:

    (function(mod) {
        this.CodeMirror = mod();
    }).call(this, function() {
      "use strict";
       (15,000-odd lines of advanced JS)
    })
    

    In the global lexical context, it is guaranteed that this will be a reference to the global context, "strict" mode or not. But if that outer immediately-invoked function is simply called, then this will be undefined in "strict" mode and the initialization would fail.