0

Among JavaScript libraries (jQuery, MathJax, marked Markdown rendering library, etc.), I often see various patterns:

Pattern #1

index.html

...
<script src="mylibrary.js"></script>
</body>
</html>

mylibrary.js

var mylibrary = (function() {
    ...
    var myVar = ...
    ...
})();

Pattern #2

index.html

<html>
<head>
...
<script src="mylibrary.js"></script>
</head>
<body>
...
</body>
</html>

Same mylibrary.js


Pattern #3

index.html

<html>
<head>
...
<script src="mylibrary.js"></script>
</head>
<body>
...
<script>
mylibrary.run();    // explicitly needs to be run
</script>
</body>
</html>

Same mylibrary.js

Questions:

  1. What's the purpose of the var mylibrary = (function() { ... })(); trick?

  2. Is there a difference between pattern #1 and #2? (I would say no)

  3. Is there any reason to prefer #3 rather than #2?
    It seems that both could be interesting. Example for MathJax: pattern #2 makes sense (it would autoparse the DOM and render math formulas), it's what has been chosen by them (see this example). Pattern #3, requiring an action to actually run the rendering would make sense as well.

Basj
  • 41,386
  • 99
  • 383
  • 673
  • See my updated answer in response to your comment. – Carl Edwards Dec 04 '16 at 20:22
  • Thanks @CarlEdwards. In short can we say that we use the IIFE pattern `var mylibrary = (function() { ... })();` more or less to add `namespaces` to Javascript? – Basj Dec 04 '16 at 20:25
  • 1
    Yes, very much so. This article might also help make better sense of this particular design pattern: https://toddmotto.com/mastering-the-module-pattern/ – Carl Edwards Dec 04 '16 at 20:27
  • @CarlEdwards Waw, thanks for this link! One of the most clearly explained document about module pattern, thanks! PS to the downvoter: I don't see why the downvote... – Basj Dec 04 '16 at 20:30
  • I wouldn't worry about it. Your question was a good one and those exact concepts stumped me for a while until I read up on these patterns and actually used them in real world context. – Carl Edwards Dec 04 '16 at 20:39

2 Answers2

1
  1. The purpose of that is that it's creating a modularized IIFE (Immediately Invoked Function Expression). This is useful to avoid polluting/assigning variables to the global namespace and helps prevent conflicts with other external plugins/dependencies that might appear in your app.

  2. Yes. In the first your scripts are loaded in the head whereas your scripts are loaded in before the closing of the body in #2. It's recommend to load your scripts before the closing of the body so your page doesn't hang as it loads in your javascript files.

  3. Go with #3 over #2. As to why, refer to point #1.

Update

Here's an example of how things would look if you were to simply assign a variable within the global namespace.

var exampleGlobal = "I'm an example global variable";

function one() {
  exampleGlobal = 1;
}

....

function two() {
  exampleGlobal.charAt(0);
}

one(); // Changes the exampleGlobal to a Number
two(); // Tries to use a string-based instance method but throws an error since exampleGlobal is now a number

Here we see that the exampleGlobal is exposed and available to all functions within this script. In this case it's very easy to err and change the value/purpose of this variable anywhere in your script. Here's where IIFE's come into play:

var exampleModule = (function() {
  var privatized = "I'm only accessible within this module";

  return {
     privatized: privatized
  }
}());

In the above we're creating just but one global variable that serves as a module and encapsulates values/functions that would only pertain exclusively to it. Try accessing privatized globally. You'll find that it returns undefined as it's not available within the global scope unless you explicitly invoke the module and it's return value:

var exampleModule = (function() {...}());

console.log(privatized); // undefined
console.log(exampleModule.privatized); // returns: "I'm only accessible within this module"

IIFE's are also advantageous in the fact that you can safely avoid naming conflicts that may occur within your app. As an example, jQuery and Mootools share the $ character to invoke their respective function calls. If you'd like to safely use the jQuery without any conflicts with Mootools you pass the $ object as an argument into your IIFE, which will then shield it from the global scope.

(function($) { // Here this is just the parameter we'd like to refer jQuery as
  $('div');
}(jQuery)); // You pass in the actual jQuery object here which is when/where the function is immediately invoked.
Carl Edwards
  • 13,826
  • 11
  • 57
  • 119
1
  1. You can't access myVar outside mylibrary.
  2. See Should I write script in the body or the head of the html?
  3. Pattern #3 gives you more control of when and how you actually use mylibrary.
Community
  • 1
  • 1
lexicore
  • 42,748
  • 17
  • 132
  • 221
  • Thanks @lexicore. If I put the script in the ``, and if this script uses IIFE, will it be executed once the DOM is finished or as soon as it is loaded? – Basj Dec 04 '16 at 20:01
  • @Basj You're making your already broad enough question even more broader by asking even more questions in comments. How about you do a quick search on SO on your own? To find something like [this](http://stackoverflow.com/questions/8996852/load-and-execute-order-of-scripts), for instance. – lexicore Dec 04 '16 at 20:07
  • I finally did [this little test](http://gget.it/33t259nc/javascriptdomorderexecution.html) @lexicore and saw that *even if I use IIFE*, if the ` – Basj Dec 04 '16 at 20:20