Concepts: The JavaScript Module Design Pattern

Product(s)
Video Cloud
Role(s)
Player Developer
Topic(s)
Developer Concepts/Tools

In this topic, you will learn how to use the JavaScript Module Design Pattern to reduce the chance that your code will conflict with other scripts on your web page.

Scope conflicts

In JavaScript, when you define a variable using the var element, it is scoped within the function that it is defined. If you define a variable without using var, then it is assigned the global scope. This means that global variables are vulnerable to collisions with other scripts on your page.

Let's look at a code example. In the following code, the function and the variables exist within the scope of the page.

// script 1
var incrementCount = function() {
    count++;
}

var myButton = document.getElementById('buttonId');
var count = 0;

myButton.onclick = incrementCount;

Now, let's say there is a function outside of your script that also modifies the global count variable. This collision of scripts can cause unexpected results.

// script 2
var countVideos = function(videoList) {
    count = videoList.length;
}

Results:

  1. User selects the myButton button two times, incrementing the count variable in script 1.
    • count = 2
  2. The countvideos function is called which exists in Script 2, but also on your web page. Let's say that the videoList contains 10 items. Now, the count global variable has a value of 10.
    • count = 10
  3. The next time the user selects the myButton button, the count variable will return unexpected results.
    • Expected: count = 3
    • Actual: count = 11

You may try to avoid conflicts in your scripts, but there is no guarantee that third-party scripts included in your page will not use similar function and variable names.

Anonymous functions

One solution is to wrap your code in an anonymous function (also called a closure), that gets executed immediately. Your code within a closure is not accessible by other scripts. So, this gives you a way to create private functions and variables.

Here is the syntax for an anonymous function:

  • Line 3: includes an additional set of parentheses, which tells JavaScript to execute the function immediately after it has been parsed, instead of waiting for some other code to call the function.
(function () {
    // your code
}());

Closures can be powerful, as they provide privacy and state throughout the lifetime of the application. For the code inside the closure, all variables and functions are in the closure scope only. But, your code inside the closure can still access any global variables or functions.

Globals

Although JavaScript has a feature known as implied globals, it may make your code hard to manage, as it is not easy to determine which variables are global. To determine if a variable is global, the interpreter has to walk backwards through the scope chain looking for a var statement that matches in name. If none is found, the variable is assumed to be global.

Pass in globals

With the anonymous function, you can explicitly pass in global parameters. This is called importing parameters into your code.

Here is an example:

  • Line 1: defines the name of the parameters being passed into the function. Notice that they do not have to match the names in line 3. Here, the window object is passed into a parameter named window1.
  • Line 3: passes the window object into the function.
(function( window1, undefined ) {
    ...
})(window);

Since there is only 1 object being passed in, but there are two parameters, the value of undefined will be undefined.

typeof undefined == "undefined"

This can be handy if you want an easy way to check if other variables are defined.

if(variable1 === undefined)

Export globals

You may also want to pass variables and functions outside of your anonymous function. You can do this by using the return value.

Here is an example:

  • Line 1: assigns our anonymous function to BCLS. This value can be anything you choose. In this example, we are using BCLS (Brightcove Learning Services).
var BCLS = (function( window1, undefined ) {
    var object1 = {};
    object1.count = 1;
    object1.method = function () {
        ...
    }
    return object1;
})(window);

The object1 object is now available globally with two public properties, a variable named count and a function named method. They can be accessed outside of our anonymous function as:

  • BCLS.object1.count
  • BCLS.object1.method

Complete examples

Here are some complete examples of the JavaScript Module Design Pattern.

Example 1

This example shows how to create private and public variables and functions using the Module Pattern.

  • Private variables: myvar, myvar2
  • Private functions: fname, fname2
  • Public variable: myvar3
  • Public function: fname3
var BCLS = ( function() {
   var myvar = value,
       myvar2 = value;

   fname = function() {
        ...
   };
   fname2 = function() {
        ...
   };

   return {
        fname3 : function() {
             ...
        },
        myvar3 = value;
   };
}());

Example 2

This example passes in global objects and exposes a public function.

var BCLS = (function( window, document, videojs ) {
    var myvar = value;

    // use a global object passed into the anonymous function
    videojs.registerPlugin('overlay');

    fname = function() {
        ...
    }
    return {
      fname2 : function() {
            ...
        }
    }
})(window, document, videojs);

// call the public function fname2
var newvar = BCLS.fname2();

Code samples

Some of our code examples use the JavaScript Module Design Pattern, and you can review them for ideas on how to implement this pattern.