JavaScript: Module as Factory, with Shared Variables

by Larry Spencer Tuesday, June 4, 2013 7:45 PM

Last time, we saw one species of JavaScript's module pattern. The module was simply a function that returned an anonymous object and hid some implementation details. Those details included a variable captured by closure.

Now we will extend the pattern to a new species of module. This time, the function will not return the object of interest, but an object that knows how to create the object we really want. The extra level of indirection provides an extra function layer in which we can hide data common to all created instances.

Here are excerpts from a JsFiddle available here

 

HTML

 

<title>Demonstration of a JavaScript Factory Module</title>
<body>
    <p>Spaceship #1 is going to <span id="spaceship1"></span>. Mission: <span id='mission1'></span>
    </p>
    <p>Spaceship #2 is going to <span id="spaceship2"></span>. Mission: <span id='mission2'></span>
    </p>
</body>

 

JavaScript

 

var spaceshipFactory = (function () {

    // This variable is shared by all spaceships.
    var mission = 'none';

    // This is spaceshipFactory's return value. It is an object
    // that knows how to create spaceships.    
    return {
        create: function () {

            // This variable is private to each created object.
            var destination = 'nowhere';

            // This is the returned value from the create method.
            // It is the interface for one spaceship.
            return {
                setDestination: function (dest) {
                    destination = dest;
                },
                getDestination: function () {
                    return destination;
                },
                setMission: function (m) {
                    mission = m;
                },
                getMission: function () {
                    return mission;
                }
            };
        }
    };
}()); // The () executes the function and puts the return value in spaceshipFactory

var s1 = spaceshipFactory.create();
var s2 = spaceshipFactory.create();
s1.setDestination('Mars');
s2.setDestination('Jupiter');
s1.setMission('To go where no man has gone before.');
$('#spaceship1').text(s1.getDestination());
$('#spaceship2').text(s2.getDestination());
$('#mission1').text(s1.getMission());
$('#mission2').text(s2.getMission());

 

Result

 

Spaceship #1 is going to Mars. Mission: To go where no man has gone before.

Spaceship #2 is going to Jupiter. Mission: To go where no man has gone before.

 

Some things to notice:

  • Instead of the spaceship function of last time, we now have a spaceshipFactory.
  • If you look closely, you'll see that spaceshipFactory is not a function, but the return value from a function that gets executed right away (the double parentheses on line 32). This return value is an object literal with just one method, namely create (line 9).
  • Create, in turn, returns an instance of a spaceship. The spaceship's interface allows you to set or get its destination and mission.
  • As in the previous post, the destination variable (line 12) is captured by closure for each spaceship. That's why each spaceship can have a separate destination in the result.
  • However, the mission variable is captured by closure as the outermost function returns. That closure happens only once, when the function is immediately executed on line 32, so there is only one instance of mission. Therefore, when the mission is set for one spaceship (line 38), it becomes the mission for all (see the result).

 

To summarize, this variant of the module pattern uses three layers of functions. We can insert variables between each layer so they get captured by closure in two useful ways: either to be shared by all instances, or to be private to each instance.

Tags: , , ,

All | General

About the Author

Larry Spencer

Larry Spencer develops software with the Microsoft .NET Framework for ScerIS, a document-management company in Sudbury, MA.