Creating Reusable Code - Pro JavaScript Techniques, Second Edition (2015)

Pro JavaScript Techniques, Second Edition (2015)

3. Creating Reusable Code

John Resig1, Russ Ferguson1 and John Paxton1

(1)

NJ, United States

In the introduction to the last chapter, we discussed objects as the fundamental unit of JavaScript. Having addressed JavaScript object literals, we will use a large portion of this chapter to examine how those objects interact with object-oriented programming. Here, JavaScript exists in a state of tension between classical programming and JavaScript’s own, nearly unique capabilities.

Moving outward from organizing our code into objects, we will look at other patterns for managing our code. We will want to ensure that we don’t pollute the global namespace, or (overly) rely on global variables. That means we will start with a discussion of namespaces, but namespaces are only the tip of the iceberg, and some newer invocation patterns are available to help us properly fence in our code: modules and, later, immediately invoked function expressions (IIFEs or “iffies”).

Once we have organized our code well within an individual file, it makes sense to look at the tools available for managing multiple JavaScript files. Certainly, we can rely on content delivery networks for some libraries we might use. But we should also think about the best way to load our own JavaScript files, lest we end up with HTML files that contain script tag after script tag after script tag.

Object-Oriented JavaScript

JavaScript is a prototypal language, not a classical language. Let’s get that out of the way up front. Java is a classical language, as everything in Java requires a class. In JavaScript, on the other hand, everything has a prototype; thus it is prototypal. But it is, as Douglas Crockford and others have said, “conflicted” about its prototypal nature. Like some reluctant superhero, JavaScript sometimes doesn’t want to stand out from the crowd of other programming languages and let its abilities shine. Well, let’s give it a cape and see what happens!

First, let’s reiterate, JavaScript is not a classical language. There are many books, blog posts, guides, slide decks, and libraries that will try to impose class-based language structures on JavaScript. You are welcome to examine them in great depth, but keep in mind that in doing so, despite good intentions, their authors are trying to hammer a square peg into a round hole. We are not trying to do that here. This chapter will not discuss how to make JavaScript act as if it were Java. Instead, we will focus on JavaScript’s intersections with capabilities outlined in object-oriented theory, and how it sometimes falls short and at other times exceeds expectations.

Ultimately, why do we want to use object-oriented programming? It provides patterns of usage that allow for simplified code reuse, eliminating duplication of effort. Also, programming in an object-oriented style helps us to think more deeply about the code that we’re working with. It provides an outline, a map, which we can follow to successful implementations. But it is not the only map. JavaScript’s prototypes are a similar but distinct way to reach our destination.

Start with the prototype itself. Every type (an Object, a Function, a Date, and so on) in JavaScript has a prototype. The ECMAScript standard specifies that this property is hidden and is referred to as [[Prototype]]. Until now, you could access this property in one of two ways: the nonstandard __proto__ property and the prototype property. At first, exposing __proto__ was not reliably available across browsers, and even when available was not always implemented the same way. [Footnote: Shocking, that browsers would implement critical parts of JavaScript differently!] With ECMAScript 6 (coming soon to a browser near you!), __proto__ will become an official property of types and will be available to any conforming implementation. But the future is not yet now.

You can also access the prototype property of certain types. All of the core JavaScript types (Date, String, Array, and so on) have a public prototype property. And any JavaScript type that is created from a function constructor also has a public prototype property. But instances of those types, be they strings, dates, or whatever, do not have a prototype property. That is because the prototype property is unavailable on instances. We will not be using the prototype property here either, because we will not use functions as constructors. We will use objects as constructors.

That’s right; we will use an object literal as the basis for other objects. If that sounds a lot like classes and instances, there are some similarities but, as you might expect, also some differences. Consider a Person object like that shown in Listing 3-1.

Listing 3-1. A Person Object

var Person = {

firstName : 'John',

lastName : 'Connolly',

birthDate : new Date('1964-09-05'),

gender: 'male',

getAge : function() {

var today = new Date();

var diff = today.getTime() - this.birthDate.getTime();

var year = 1000 * 60 * 60 * 24 * 365.25;

return Math.floor(diff / year);

}

};

Nothing remarkable here: a person has a first name, a last name, a gender, a birth date and a way to calculate their age. This Person is an object literal, not really anything we’d recognize as being class-like. But we want to use this Person as if it were a class. We want to create more objects that conform to the structure that Person has set forth. To preserve the distinction between classless JavaScript and object-oriented languages that have classes, we will refer to Person as a type (similar to the way Date, Array, and RegExp are all types). We want to create instances of the Person type: to do so, we can use Object.create (Listing 3-2).

Listing 3-2. Creating People

var Person = {

firstName : 'John',

lastName : 'Connolly',

birthDate : new Date( '1964-09-05' ),

gender : 'male',

getAge : function () {

var today = new Date();

var diff = today.getTime() - this.birthDate.getTime();

var year = 1000 * 60 * 60 * 24 * 365.25;

return Math.floor( diff / year );

},

toString : function () {

return this.firstName + ' ' + this.lastName + ' is a ' + this.getAge() +

' year-old ' + this.gender;

}

};

var bob = Object.create( Person );

bob.firstName = 'Bob';

bob.lastName = 'Sabatelli';

bob.birthDate = new Date( '1969-06-07' );

console.log( bob.toString() );

An instance has been created from the Person object. We are storing an instance of Person in the variable bob. No classes. But there is a link between the Person objects we created and the Person type. This link is over the [[Prototype]] property. If you are running a sufficiently modern browser (at the time of this writing, this worked in IE11, Firefox 27, and Chrome 33), you can open the console in the developer tools and look at the __proto__ property on bob. You’ll note that it points to the Person object. In fact, you can test this by checking that bob.__proto__ === Person.

Object.create was added to JavaScript with ECMAScript 5, ostensibly to simplify and clarify the relationship between objects, particularly which objects were related by their prototype. But in doing so, it allowed for a simple, one-step creation of that relationship between objects. This relationship feels very much like the object-oriented idea of the class and the instance. But because JavaScript has no classes, we simply have objects with a relationship between each other.

This relationship is often referred to as the prototype chain. In JavaScript, the prototype chain is one of two places that are examined to resolve the value of a member of an object. That is, when you refer to foo.bar or foo[bar], the JavaScript engine looks up the value of bar in two potential places: on foo itself, or on foo’s prototype chain.

In his three-part essay on object-oriented JavaScript ( http://davidwalsh.name/javascript-objects ), Kyle Simpson makes an elegant point about how we should look at this process. Instead of seeing bob’s relationship to Person as that of an instance to a class, or a child to a parent, we should see it as a case of behavior delegation. The bob object has its own firstName and lastName, but it does not have any getAge functionality. That is delegated to Person. The delegate relationship is established through the use of Object.create. The prototype chain is the mechanism of this delegation, allowing us to delegate behavior to something further along the chain. Viewed from bob’s perspective, functionality accumulates as we successively invoke Object.create, layering on additional capabilities.

By the way, you might be concerned that you have a browser that doesn’t support ECMAScript 5 or at least doesn’t have its version of Object.create. This isn’t a problem; Object.create can be polyfilled quite easily across any browser with a JavaScript engine, as shown in Listing 3-3.

Listing 3-3. An Object.create Polyfill

if ( typeof Object.create !== 'function' ) {

Object.create = function ( o ) {

function F() {

}

F.prototype = o;

return new F();

};

}

Finally, some people don’t like the idea of constantly using Object.create to, well, create objects. They feel more at home with the typical phrasing of someInstance = new Type(); If that’s the case, consider the quick modification to the Person object in Listing 3-4, which provides a factory method for generating more Persons.

Listing 3-4. The Person Object with a Factory Method

var Person = {

firstName : 'John',

lastName : 'Connolly',

birthDate : new Date( '1964-09-05' ),

gender : 'male',

getAge : function () {

var today = new Date();

var diff = today.getTime() - this.birthDate.getTime();

var year = 1000 * 60 * 60 * 24 * 365.25;

return Math.floor( diff / year );

},

toString : function () {

return this.firstName + ' ' + this.lastName + ' is a ' + this.getAge() +

' year-old ' + this.gender;

},

extend : function ( config ) {

var tmp = Object.create( this );

for ( var key in config ) {

if ( config.hasOwnProperty( key ) ) {

tmp[key] = config[key];

}

}

return tmp;

}

};

var bob = Person.extend( {

firstName : 'Bob',

lastName : 'Sabatelli',

birthDate : new Date( '1969-06-07' )

} );

console.log( bob.toString() );

Here, the extend function encapsulates the call to Object.create. When extend is called, it invokes Object.create internally. Presumably, extend is invoked with a configuration object passed in, a fairly typical JavaScript usage pattern. By looping over the properties in tmp, the extend function also ensures that only the properties of the config already present on the tmp object are extended onto the newly created tmp object. Once we’ve copied the properties from config to tmp, we can return tmp, our instance of a Person.

Now that we’ve looked at the new style of setting up relationships between objects in JavaScript, let us see how it affects JavaScript’s interactions with typical object-oriented concepts.

Inheritance

By far, the biggest question mark has to be inheritance. Much of the point of object-oriented code is to reuse functionality by working from general parent classes to more specific child classes. We have already seen that it is easy to create a relationship between two objects withObject.create. We can simply extend that usage to create whatever sort of inheritance hierarchy we prefer. (OK, whatever sort of single-inheritance hierarchy we prefer. Object.create does not allow multiple inheritance.) Remember the idea that we are delegating behavior; as we create subclasses with Object.create, they are delegating some of their behavior to types further up the prototype chain. Inheritance with Object.create tends to be more of a bottom-up affair, rather than the typically top-down object oriented style.

Inheritance is actually quite simple: use Object.create. To elaborate, use Object.create to create a relationship between the “parent” type and the “child” type. The child type can add functionality, delete functionality, or override existing functionality. Call Object.create with an argument of whatever object you decide is your “parent” type, and the returned value will be whatever you decide your “child” type is. Then repeat the pattern from Listing 3-4 and use the extend method (or reuse Object.create!) to create instances of that child type (Listing 3-5).

Listing 3-5. Person Is the Parent of Teacher

var Person = {

firstName : 'John',

lastName : 'Connolly',

birthDate : new Date( '1964-09-05' ),

gender : 'male',

getAge : function () {

var today = new Date();

var diff = today.getTime() - this.birthDate.getTime();

var year = 1000 * 60 * 60 * 24 * 365.25;

return Math.floor( diff / year );

},

toString : function () {

return this.firstName + ' ' + this.lastName + ' is a ' + this.getAge() +

' year-old ' + this.gender;

},

extend : function ( config ) {

var tmp = Object.create( this );

for ( var key in config ) {

if ( config.hasOwnProperty( key ) ) {

tmp[key] = config[key];

}

}

return tmp;

}

};

var Teacher = Person.extend( {

job : 'teacher',

subject : 'English Literature',

yearsExp : 5,

toString : function () {

return this.firstName + ' ' + this.lastName + ' is a ' + this.getAge() +

' year-old ' + this.gender + ' ' + this.subject + ' teacher.';

}

} );

var patty = Teacher.extend( {

firstName : 'Patricia',

lastName : 'Hannon',

subject: 'chemistry',

yearsExp : 20,

gender : 'female'

} );

console.log( patty.toString() );

Object.create established a link between the [[Prototype]] of Teacher and the [[Prototype]] of Person. If you have one of the modern browsers mentioned earlier, you should be able to look at the __proto__ property of Teacher and see that it points to Person.

In Chapter 2, we talked about instanceof as a way to find out whether an object is an instance of a type. The instanceof operator will not work here. It relies on the explicit prototype property to trace the relationship of an object to a type. Put more simply, the right-hand operand ofinstanceof must be a function (though most likely a function constructor). The left-hand operand must be something that was created from a function constructor (though not necessarily the function constructor on the right). So how can we tell if an object is an instance of a type? Enter theisPrototypeOf function.

The isPrototypeOf function can be invoked on any object. It is present on all JavaScript objects, much like toString. Invoke it on the object that is fulfilling the role of the type (Person or Teacher, in our examples so far) and pass it an argument of the object that is fulfilling the role of an instance (bob or patty). Therefore, Teacher.isPrototypeOf(patty) will return true, as you would expect. Listing 3-6 provides the code that looks at combinations of Teachers, Persons, bob, and patty and invocations of isPrototypeOf.

Listing 3-6. The isPrototypeOf() Function

var Person = {

firstName : 'John',

lastName : 'Connolly',

birthDate : new Date( '1964-09-05' ),

gender : 'male',

getAge : function () {

var today = new Date();

var diff = today.getTime() - this.birthDate.getTime();

var year = 1000 * 60 * 60 * 24 * 365.25;

return Math.floor( diff / year );

},

toString : function () {

return this.firstName + ' ' + this.lastName + ' is a ' + this.getAge() +

' year-old ' + this.gender;

},

extend : function ( config ) {

var tmp = Object.create( this );

for ( var key in config ) {

if ( config.hasOwnProperty( key ) ) {

tmp[key] = config[key];

}

}

return tmp;

}

};

var Teacher = Person.extend( {

job : 'teacher',

subject : 'English Literature',

yearsExp : 5,

toString : function () {

return this.firstName + ' ' + this.lastName + ' is a ' + this.getAge() +

' year-old ' + this.gender + ' ' + this.subject + ' teacher.';

}

} );

var bob = Person.extend( {

firstName : 'Bob',

lastName : 'Sabatelli',

birthDate : new Date( '1969-06-07' )

} );

var patty = Teacher.extend( {

firstName : 'Patricia',

lastName : 'Hannon',

subject: 'chemistry',

yearsExp : 20,

gender : 'female'

} );

console.log( 'Is bob an instance of Person? ' + Person.isPrototypeOf(bob) ); // true

console.log( 'Is bob an instance of Teacher? ' + Teacher.isPrototypeOf( bob ) ); // false

console.log( 'Is patty an instance of Teacher? ' + Teacher.isPrototypeOf( patty ) ); // true

console.log( 'Is patty an instance of Person? ' + Person.isPrototypeOf( patty ) ); // true

There is a companion function to isPrototypeOf; it’s named getPrototypeOf. Called as Object.getPrototypeOf(obj), it returns a reference to the type that was the basis for the current object. As noted, you can also look at the (currently nonstandard but soon to be standard) __proto__ property for the same information (Listing 3-7).

Listing 3-7. getPrototypeOf

console.log( 'The prototype of bob is Person' + Object.getPrototypeOf( bob ) );

What about accessing overridden methods? It is, of course, possible to override a method from the parent object in the child object. There is nothing special about this capability, and it’s expected in any object-oriented system. But in most object-oriented systems, an overridden method has access to the parent method via a property or accessor called something like super. That is, when you are overriding a method, you can usually call the method you are overriding via a special keyword.

We do not have that available here. JavaScript’s prototype-based object-oriented code simply does not have a super() feature. There are, generally, three ways to solve this problem. First, you could write some code to reimplement super. This would involve traversing back up the prototype chain, probably with getPrototypeOf, to find the object in the inheritance chain that had the previous edition of the method you’re overriding. (Remember, you aren’t always overriding something in the parent; it could be something from the “grandparent” class, or something further up the prototype chain.) Then you would need some way to access that method and call it with the same set of arguments passed to your overriding method. This is certainly possible, but it tends to be ugly and quite inefficient at the same time.

As a second solution, you could explicitly call the parent’s method as shown in Listing 3-8.

Listing 3-8. Reproducing the Effect of the super Function

var Person = {

firstName : 'John',

lastName : 'Connolly',

birthDate : new Date( '1964-09-05' ),

gender : 'male',

getAge : function () {

var today = new Date();

var diff = today.getTime() - this.birthDate.getTime();

var year = 1000 * 60 * 60 * 24 * 365.25;

return Math.floor( diff / year );

},

toString : function () {

return this.firstName + ' ' + this.lastName + ' is a ' + this.getAge() +

' year-old ' + this.gender;

},

extend : function ( config ) {

var tmp = Object.create( this );

for ( var key in config ) {

if ( config.hasOwnProperty( key ) ) {

tmp[key] = config[key];

}

}

return tmp;

}

};

var Teacher = Person.extend( {

job : 'teacher',

subject : 'English Literature',

yearsExp : 5,

toString : function () {

var originalStr = Person.toString.call(this);

return originalStr + ' ' + this.subject + ' teacher.';

}

} );

var patty = Teacher.extend( {

firstName : 'Patricia',

lastName : 'Hannon',

subject: 'chemistry',

yearsExp : 20,

gender : 'female'

} );

console.log( patty.toString() );

Pay particular attention to the toString method in Teacher. You will note that Teacher’s toString function makes an explicit call to Person’s toString function. Many object-oriented designers would argue that we should not have to hard-code the relationship between Person and Teacher. But as a simple means to an end, doing so does solve the problem quickly, neatly, and efficiently. On the other hand, it’s not portable. This approach will only work for objects that are somehow related to the Parent object.

The third possibility is that we could simply not worry about whether we have super at all. Yes, JavaScript the language lacks the super feature, which is present in many other object-oriented languages. But that feature is not the be-all, end-all of object-oriented code. Perhaps in the future, JavaScript will have a super keyword with the appropriate functionality. (Actually, it is known that in ECMAScript 6, there is a super property for objects.) But for now, we can get along quite well without it.

Member Visibility

In object-oriented code, we often want to control the visibility of our objects’ data. Most of our members, whether functions or properties, are public, in keeping with JavaScript’s implementation. But what if we need private functions or private properties? JavaScript does not have easy, straightforward visibility modifiers (like “private” or “protected” or “public”) that control who can access a member of a property. But you can have the effect of private members. Further, you can provide special access to those private members through what Douglas Crockford calls a privileged function.

Recall that JavaScript has only two scopes: global scope and the scope of the currently executing function. We took advantage of this in the previous chapter with closures, a critical part of implementing privileged access to private members. It works this way: create private members using var inside the function that builds your object. (Whether those private members are functions or properties is up to you.) In the same scope, create a function; it will have implied access to the private data, because both the function and the private data belong to that same scope. Add this new function to the object itself, making the function (but not the private data) public. Because the function comes from the same scope, it can still access that data indirectly. Look at Listing 3-9 for details.

Listing 3-9. Private Members

var Person = {

firstName : 'John',

lastName : 'Connolly',

birthDate : new Date( '1964-09-05' ),

gender : 'male',

getAge : function () {

var today = new Date();

var diff = today.getTime() - this.birthDate.getTime();

var year = 1000 * 60 * 60 * 24 * 365.25;

return Math.floor( diff / year );

},

toString : function () {

return this.firstName + ' ' + this.lastName + ' is a ' + this.getAge() +

' year-old ' + this.gender;

},

extend : function ( config ) {

var tmp = Object.create( this );

for ( var key in config ) {

if ( config.hasOwnProperty( key ) ) {

tmp[key] = config[key];

}

}

// When was this object created?

var creationTime = new Date();

// An accessor, at the moment, it's private

var getCreationTime = function() {

return creationTime;

};

tmp.getCreationTime = getCreationTime;

return tmp;

}

};

var Teacher = Person.extend( {

job : 'teacher',

subject : 'English Literature',

yearsExp : 5,

toString : function () {

var originalStr = Person.toString.call(this);

return originalStr + ' ' + this.subject + ' teacher.';

}

} );

var patty = Teacher.extend( {

firstName : 'Patricia',

lastName : 'Hannon',

subject: 'chemistry',

yearsExp : 20,

gender : 'female'

} );

console.log( patty.toString() );

console.log( 'The Teacher object was created at %s', patty.getCreationTime() );

As you can see, the creationTime variable is local to the extend function. It is not available outside that function. If you were to examine Person on the console with, say, console.dir, you would not see creationTime listed as a public property of Person. Initially, the same is true forgetCreationTime. It is a function that was created at the same scope as creationTime, so the function has access to creationTime. Using simple assignment, we attach getCreationTime to the object instance we are returning. Now, getCreationTime is a public method, with privileged access to the private data in creationTime.

A minor caveat: this is not the most efficient of patterns. Every time you create an instance of Person, or any of its child types, you will be creating a brand-new function with access to the execution context of the call to extend that created the instance of Person. By contrast, when we useObject.create, our public functions are references to those on the type we pass into Object.create. Privileged functions are not particularly inefficient at the small scale we are dealing with here. But if you added more privileged methods, they would each retain a reference to that execution context, and each would be its own instance of that privileged method. The memory costs can multiply quickly. Use privileged methods sparingly, reserving them for data that needs strict access control. Otherwise, become comfortable with the notion that most data in JavaScript is public anyway.

The Future of Object-Oriented JavaScript

We would be remiss in overlooking the fact that there are some changes coming to object-oriented JavaScript with ECMAScript 6. The most important of these changes is the introduction of a working class keyword. The class keyword will be used to define JavaScript types (not classes, as JavaScript still won’t have classes!). It will also include provisos for the use of the keyword extends to create an inheritance relationship. Finally, when overriding functions in a child type, ECMAScript 6 sets aside the super keyword to refer to the version of the function on the prototype chain.

All of this is syntactic sugar, though. When these structures are desugared by the JavaScript engine, they are revealed to be uses of functional constructors. These new features do not actually establish new functionality: they simply introduce an idiom more palatable to programmers from other object-oriented languages. Worse, they continue to obscure some of the best features of JavaScript by trying to have it conform to these other languages’ notions of what a “true” object-oriented language should look like. It appears that sometimes, JavaScript is still a little shy about putting on the cape and tights before using its powers for good.

Packaging JavaScript

Moving outward from object-oriented JavaScript, we should consider how to organize our code for broad reuse. We want a set of tools for properly encapsulating our code, preventing accidental use of the global context, as well as ways to make our code reusable and redistributable. Let’s tackle the various requirements in order.

Namespaces

So far, we have declared our types (and earlier, our functions and variables) to be part of the global context. We have not done this explicitly, but by virtue of the fact that we have not declared these objects and variables to be part of any other context. We would like to encapsulate functions, variables, objects, types, and so on into a separate context, so as not to rely on the global context. To do so, we will rely (initially) on namespaces.

Namespaces are not unique to JavaScript, but, as is the case with so many things in JavaScript, they are a little different from what you might expect. A namespace provides a context for variables and functions. The namespace itself is likely to be global, of course. This is a lesser-of-two-evils approach. Instead of having numerous variables and functions belonging to the window, we can have one variable belong to the window, and then a variety of data and functionality belong to that one variable. The implementation is simple: use an object literal to encapsulate the code that you want to hide from the global context (Listing 3-10).

Listing 3-10. Namespaces

// Namespaces example

var FOO = {};

// Add a variable

FOO.x = 10;

// Add a function

FOO.addEmUp = function(x, y) {

return x + y;

};

Namespaces are best used as ad-hoc solutions to the encapsulation of otherwise unaffiliated code. If we try to use namespaces for all our code, they can quickly become unwieldy, as they accrete more and more functionality and data. You might be tempted to set up namespaces within namespaces, emulating something of the way packages work with Java. The Ext JS library uses this technique well, for what it’s worth. But they also have spent a lot of time thinking about how to organize their functionality, what code belongs to what namespace or sub-namespace, and so on. There are trade-offs with extensive use of namespaces.

Also, namespace names are hard-coded: FOO in the example, Ext in the case of the aforementioned library Ext JS, YAHOO in the case of the similarly popular YUI library. These namespaces are effectively reserved words for those libraries. What happens if two or more libraries settle on the same namespace (as with jQuery’s use of $ as a namespace)? Potential conflicts. JQuery has added explicit code to deal with this possibility, should it arrive. Although this issue is potentially less likely with your own code, it is a possibility that has to be considered. This is especially true in a team environment where multiple programmers have access to the namespace, raising the possibility of accidentally overwriting or deleting another coder’s namespace.

The Module Pattern

We have some tools for improving the way we use namespaces. We can work with the module pattern, which encapsulates generation of the namespace within a function. This allows for a variety of improvements, including establishing a baseline for what functions and data the namespace contains, use of private variables within the generator function, which might make implementation of some functionality easier, and simply having a function generate the namespace, which means that we can have JavaScript dynamically generate part or all of the namespace at runtime instead of at compile-time.

Modules can be as simple or as complex as you prefer. Listing 3-11 provides a very simple example of creating a module.

Listing 3-11. Creating a Module

function getModule() {

// Namespaces example

var FOO = {};

// Add a variable

FOO.x = 10;

// Add a function

FOO.addEmUp = function ( x, y ) {

return x + y;

};

return FOO;

}

var myNamespace = getModule();

We have encapsulated our namespace code inside a function. Thus, when we initially set up the FOO object, it is private to the getModule function. We can then return FOO to anyone who invokes getModule, and they can use the encapsulated structure as they see fit, including naming it whatever they want.

Another advantage to this pattern is that we can once again utilize our friend the closure to set up data that is private only to the namespace. If our namespace, our encapsulated code, needs to have internal data or internal functions, we can add them without worrying about making them public (Listing 3-12).

Listing 3-12. Modules with Private Data

function getModule() {

// Namespaces example

var FOO = {};

// Add a variable

FOO.x = 10;

// Add a function

FOO.addEmUp = function ( x, y ) {

return x + y;

};

// A private variable

var events = [];

FOO.addEvent = function(eventName, target, fn) {

events.push({eventName: eventName, target: target, fn: fn});

};

FOO.listEvents = function(eventName) {

return events.filter(function(evtObj) {

return evtObj.eventName === eventName

});

};

return FOO;

}

var myNamespace = getModule();

In this example, we have implemented a public interface for adding some sort of event tracking with addEvents. Later, we might want to get back event references by their names via listEvents. But the actual events collection is private, managed by the public API we provide to it, but hidden from direct access.

Modules, like namespaces, have the same problem of being a lesser-of-two-evils approach. We have traded a global variable for our namespace for a global function getModule. Wouldn’t it be nice if we could have full control over what winds up in the global namespace, without necessarily using globally scoped objects or functions to do so? Luckily, we are about to see a tool that can help us do exactly that.

Immediately Invoked Function Expressions

If we want to avoid polluting the global namespace, functions are the logical solution. Functions create their own execution context when they are running, which is subordinate to but insulated from the global namespace. When the function finishes running, the execution context is available for garbage collection and the resources dedicated to it can be reclaimed. But all of our functions have been either global or part of a namespace, which is itself global. We would like to have a function that can immediately execute, without having to be named and without having to be part of a namespace or context, global or otherwise. Then, within that function, we could build the module that we need. We could return such an object, export it, and make it otherwise available, but we would not have to have a public function around to take up resources generating it. This is the idea behind the immediately invoked function expression (IIFE).

All of the functions we have worked with to this point have been function declarations. Whether we define them as function funcName { ... } or var funcName = function() { ... }, we are declaring functions, reserving their usage for later. Can we instead create a function expression, which would be a function that is created and executed in one fell swoop? The answer is yes, but doing so will require a degree of syntactical intrepidity.

How do we execute functions? Typically, with a named function, we print the name of the function, and then append some parentheses afterwards, indicating we want to execute the code associated with that name. We cannot do the same with a function definition, in and of itself. The result would be a SyntaxError, obviously not what we want.

But we can put the function declaration inside a set of parentheses, a hint to the parser that this is not a statement but an expression. Parentheses cannot contain statements, but only code to be evaluated as an expression, which is what we want out of our function. We need one more bit of syntax to make this work, another set of parentheses, usually at the end of the function declaration itself. Listing 3-13 will illuminate the full syntax.

Listing 3-13. An Immediately Invoked Function Expression

// A regular function

function foo() {

console.log( 'Called foo!' );

}

// Function assignment

var bar = function () {

console.log( 'Called bar!' );

};

// Function expression

(function () {

console.log( 'This function was invoked immediately!' )

})();

// Alternate syntax

(function () {

console.log( 'This function was ALSO invoked immediately!' )

}());

Compare and contrast the first two functions, which are function declarations, with the latter two, which are function expressions. The expressions are wrapped in parentheses to “expressionize” them (or, if you prefer: “de-declarify” them) and then use a second set of parentheses to invoke the expression. Nifty!

As an aside, there are a variety of JavaScript syntactical particles that will result in IIFEs: functions as components of a logical evaluation, unary operators prefixed to a function declaration, and so on. “Cowboy” Ben Alman’s article on IIFEs (http://benalman.com/news/2010/11/immediately-invoked-function-expression/ ) contains terrific detail on valid syntaxes and goes deep into the guts of how IIFEs work and how they came to be.

Now that we know how to create an IIFE, how do we use it? There are many applications of IIFEs, but the one we’re concerned with here is the generation of a module. Can we capture the result of an IIFE into a variable? Of course! So we can wrap our module generator in an IIFE and have it return the module (Listing 3-14).

Listing 3-14. An IIFE Module Generator

var myModule = (function () {

// A private variable

var events = [];

return {

x : 10,

addEmUp : function ( x, y ) {

return x + y;

},

addEvent : function ( eventName, target, fn ) {

events.push( {eventName : eventName, target : target, fn : fn} );

},

listEvents : function ( eventName ) {

return events.filter( function ( evtObj ) {

return evtObj.eventName === eventName

} );

}

};

})();

We have changed a few things in this last example. First, and simplest, we are now capturing the output of our factory IIFE in myModule instead of myNamespace. Second, instead of creating an object and then returning it, we are returning the object directly. This simplifies our code, cutting down on reserving a space for an object we ultimately never use.

The IIFE pattern opens up many new possibilities, including the use of libraries or other tools as needed. The parentheses at the end of our function expression are the same parentheses we expect on a regular function invocation. Therefore, we can pass arguments into our IIFE and use them within. Imagine an IIFE that had access to jQuery functionality (Listing 3-15).

Listing 3-15. Passing Arguments to an IIFE

// Here, the $ refers to jQuery and jQuery only for the entire

// scope of the module

var myModule = (function ($) {

// A private variable

var events = [];

return {

x : 10,

addEmUp : function ( x, y ) {

return x + y;

},

addEvent : function ( eventName, target, fn ) {

events.push( {eventName : eventName, target : target, fn : fn} );

$( target ).on( eventName, fn );

},

listEvents : function ( eventName ) {

return events.filter( function ( evtObj ) {

return evtObj.eventName === eventName

} );

}

};

})(jQuery); // Assumes that we had included jQuery earlier

We pass jQuery into our IIFE, and then refer to it as $ throughout the IIFE. Internally, it’s used within the addEvent function to add an event handler to the DOM. (Don’t worry if the syntax does not make sense; it isn’t the core of the example!)

Based on this code, you can probably imagine a system where modules generated by IIFEs talk to each other, passing arguments back and forth and using libraries, all without necessarily interacting at the global level. In fact, that is part of what the next chapter is about.

Summary

The problem before us at the start of this chapter was one of code management. How can we write code in such a way as to follow good object-oriented guidelines, and how can we encapsulate that code for reusability? In the former case, we concentrated on JavaScript’s prototypal nature, using it to generate something similar to classes and instances, but with a unique JavaScript spin on it. And the implementation was a lot simpler than attempting to force JavaScript to act like C# or Java. For the latter requirement, we worked our way through a variety of solutions that enable us to encapsulate our code: namespaces, modules, and immediately invoked function expressions. Ultimately, a combination of all three provided us with the best-case solution for least use of the global context.