A Programmer’s Tour Of Javascript

Functions as Constructors

To create a new object using a JavaScript function, simply place the keyword new in front of a call to that function. The object that is created is a plain ol’ JavaScript object; using the typeof operator on it will return "object", not "function".

“But wait,” I hear you ask, despite the fact that you’re not here, “how does JavaScript know the difference between a constructor and a regular function?”

It doesn’t. As far as JavaScript is concerned, any function can be used as a constructor. Because of this, it is a convention among JavaScript programmers to make constructor functions start with an upper-case letter.

You’ve already seen this with wrapper functions. Simply calling the String function will convert the parameter to a string primitive, but using the new keyword will create a String object. The principle is the same for all JavaScript functions.

If your function returns an object, that will be the new object that is created; otherwise, the return value is completely ignored. The function’s parameters and declared variables will still have function-local scope – they don’t turn into properties or anything like that. So, unless you explicitly say so, the object that is constructed won’t have any members or methods, other than those that it inherits from Object.

Well, how do we change that behavior? If we are writing a constructor, how do we make the constructor create properties and methods?

Within constructors, this is done using the this keyword. You’ve probably seen it in Java or C++, where it explicitly refers to the current object. In JavaScript, it is a little more complicated. JavaScript doesn’t distinguish between functions, constructors, or methods, so this can mean a whole bunch of different things.

What this Means

In JavaScript, this implicitly references the invoking object. So this can reference different objects, depending upon the context of the function call.

There are several rules that determine what this references. Douglas Crockford calls each rule an invocation pattern, and he’s smarter than me, so I’ll follow his lead.

To better understand these rules, let’s see how they all apply to the same function when it is invoked in different contexts:

function setName(n) {
    this.name = "" + n; // make sure it's a string primitive
}

Anyone coming from C++ or Java will recognize this as a simple “setter” function. But what name does it set?

Constructor Invocation
When a function is invoked as a constructor, this refers to the constructed object.

You use this invocation pattern to add properties and methods when you are writing a constructor function. To assign a member called, say, “prop” to your constructed object, simply assign a value to this.prop. If that value is a primitive type or object, it will be a property; if it’s a function object (anonymous or otherwise), it will be a method.

So, in our setter example, we would be adding a name property to the constructed object, and setting its value to the argument that was passed to the constructor. If you’re coming from C++ or Java, this is exactly the behavior you’d expect.

Let’s see a better example of a constructor that uses this. Here’s a function that constructs Person objects:

function Person() {
    this.name = "Human";
    this.setName = function(n) {
        this.name = "" + n;
    }
}
> var bob = new Person();
  Person {name: "Human", setName: function}
> bob.name;
  "Human"
> bob.setName("Bobby");
  undefined;
> bob.name;
  "Bobby"
Method Invocation
When a function is invoked as a method of an object, this refers to the object that invoked it.

Again, if you’re coming from C++ or Java, this is exactly the behavior you’d expect. But there are two “gotchas” to keep in mind. The first is that all JavaScript objects, including this, are dynamic. So if this.name wasn’t already set (say, in the constructor), that property would be created by the setName method. That’s probably not what we intended; more likely, we had a typo in the property name.

The second “gotcha” is that all objects are assigned by reference, including function objects. So if you pass an object’s method to another function, or assign it to a variable, then the context of this is lost. A common source of this problem is using an object’s method as a callback function.

When a method’s this context is lost, the function is usually invoked as a global function; see below for an example.

Global Function Invocation
When a function is invoked as a global (“stand-alone”) function, this refers to the global object.

If you simply invoke the setName function above, it will create a global variable called “name,” and assign it the value of whatever was passed as a parameter. A common term for this is polluting the global namespace. As you might guess, it is generally considered a terrible idea.

The most common cause of global namespace pollution is when a constructor is invoked without using the new keyword. Unfortunately, it is pretty easy to leave out three letters, so it’s a very common mistake. I will show you some solutions a little later in the article.

Another common cause is when a method’s context is lost. I mentioned it above, but now let’s see an example. Imagine that our “setter” code actually was a setter method of an object:

var bob = {
    name: "Bob",
    setName: function(n) {
        this.name = n;
    }
}
var nameBob = bob.setName;

What happens if we try to change bob‘s name using the nameBob function?

> nameBob("Bobby");
  undefined
> bob.name;
  "Bob"
> name;
  "Bobby"

Because bob.setName was assigned to nameBob by reference, the context of this was lost. Instead of referring to the bob object, it refers to the global object, a.k.a. the global namespace.

DOM Event Listener Invocation
When a function is invoked as a DOM event listener, this usually refers to the DOM object that fired the event.

We haven’t covered the DOM (Document Object Model) yet. I will talk about it when I talk about the JavaScript environment. There are a host of “gotchas” with this rule, and I’ll cover them at that point. For now, just take it on faith.

Explicit Binding
When a function is invoked using one of its explicit binding methods, this refers to whatever you want.

Let’s say that none of the implicit binding rules do what you want, or that you just don’t want to worry about them. JavaScript functions have methods that let you call the function using any object as the context.

Two of those methods are call() and apply(). They work almost identically. Both take the context (what you want this to reference) as the first argument. The only difference between them is the remaining arguments: call() takes a variable number of arguments, while apply() takes a single array of arguments.

There is a third method named bind() that does something similar, but it is not implemented in older browsers.

Solving the problems of this

Now we know one way a JavaScript constructor creates properties of an object: it declares them using the this object. One problem with this was presented above: in many cases, it can refer to the global object, so defining properties on this will pollute the global namespace. There are a couple of solutions to that problem.

One solution is to explicitly check the type of this inside the constructor. You can do this using the instanceof operator. This returns true if the object on the left-hand side was constructed with the function on the right-hand side. (I will discuss how JavaScript “knows” this when I talk about prototypes.) If that’s not the case, then we recursively call the constructor function using the new keyword, and return that object instead. Here’s how we would modify the Person constructor:

function Person() {
    // Make sure we're using the function as a constructor
    if ( !(this instanceof Person) ) {
        return new Person();
    }
    this.name = "Human";
    this.setName = function(n) {
        this.name = "" + n;
    }
}

Another way that global namespace pollution can be avoided is by using strict mode. Among other things, strict mode disallows the alteration of the global object through the this keyword. To use strict mode, insert the string literal "use strict" as the very first line of your code. It is scope-sensitive, so it can be set either on your entire script, or on a specific function.

Unfortunately, strict mode was only introduced in ECMAScript 5, so it’s not supported in many browsers (for example, IE 9 and below). There are also problems with mixing strict and non-strict code. For more information see the Strict mode article from the Mozilla Developer Network.

If you are coming from a classical object-oriented language, you will see another issue. JavaScript has no access modifiers, so the properties you define on this are all public. Is there any way to change that?

In fact, there is – but it comes at a price. A function’s parameters and defined variables have function-local scope, and the constructor is just a function. This means that we can use closures to create privileged methods – methods that are themselves public, but have access to private data.

The code itself is very straightforward. Let’s alter our Person constructor so that name is a private variable, which is only accessed by privileged getter and setter methods:

function Person(name) {
    this.getName = function() {
        return name;
    }
    this.setName = function(n) {
        name = "" + n;
    }
}

Both the getName and setName methods are public properties of the constructed object, but they use the Person function’s name parameter. JavaScript creates a closure that includes that parameter in its environment, so both methods can access that parameter, even though it is not a property of the object itself.

> var bob = new Person("Bob");
  Person {getName: function, setName: function}
> bob.name;
  undefined
> bob.getName();
  "Bob"
> bob.setName("Bobby");
  undefined
> bob.getName();
  "Bobby"

Here’s another advantage. The name parameter is not accessed using the this keyword. So, it’s not possible to lose the context when you assign the method to a variable, or pass it as an argument. The closure ensures that it will always reference the private parameter:

> var nameBob = bob.setName;
  undefined
> nameBob("Bobbiekins");
  undefined
> bob.getName();
  "Bobbiekins"

Of course, that does not entirely solve the problem of polluting the global namespace. If you call the constructor function without the new keyword, you’re still going to create the getName and setName properties on the global object. You still have to use strict mode or do explicit type checking.

Another technique is to create and return an anonymous object, using object literal notation, and set the properties of that object to the privileged methods. If the new keyword is used, then the returned object is the one that gets constructed. If the new keyword isn’t used, then the same object gets returned anyway.

Let’s re-write the Person constructor to use this technique:

function Person(name) {
    return {
        getName: function() {
            return name;
        },
        setName: function(n) {
            name = "" + n;
        }
    };
}

Now, there’s no chance of polluting the global namespace, and you still get all the advantages of using closures:

> var bob = new Person("Bob");
  Person {getName: function, setName: function}
> bob.getName();
  "Bob"
> var bill = Person("Bill"); // Oops!
  Person {getName: function, setName: function}
> bill.getName();
  "Bill"
> getName();
  ReferenceError: getName is not defined

This technique is more commonly used to create singletons (unique objects) in the global namespace. Instead of a constructor, you use an IIFE. Here’s an example that is slightly more complicated:

var Bob = (function(name) {
    function get() {
        return name;
    }
    function set(n) {
        name = toString(n);
    }
    function toString(s) {
        return "" + s;
    }
    return {
        getName: get,
        setName: set
    };
})("Bob");

This technique is called the revealing module pattern. The IIFE syntax makes it a little clearer that you are using a closure. It also makes it clear why the pattern has the name it does. If you use an IIFE in this way, you are creating a unique global object that acts like its own programming module. The object that is returned contains only the public interface to the module – the parts that are “revealed.” In the above example, the toString() function is private, but still usable by the privileged set() method; not only that, but it does not interfere with the global toString() function.

Every object with private variables will create a unique closure for every method. This isn’t so bad for a module (since it is designed to be unique anyway), but it is for a constructor. For example, our Person constructor creates two closures: one each for getName and setName. If you have ten different Person objects, you have twenty different function objects and their referenced environments, all taking up memory. Plus, when these objects go out of scope, they need to be garbage collected, and this will cause a performance impact.

Unfortunately, if you want private members, there’s no way around it. If you’re writing high-performance JavaScript, you shouldn’t use private variables at all. Luckily, performance is less of an issue if you’re only writing JavaScript code to run on a desktop browser. It is mainly an issue if you’re writing JavaScript applications for phones or tablets. Still, efficient code is always better, so if you don’t absolutely need private variables, don’t use them.

But this problem isn’t limited to closures; it happens every time you declare methods inside a constructor. A new function is declared and assigned to each method, so each constructor call will create another batch of function objects. Since this is dynamically bound to whichever object is invoking the method, creating a bunch of identical function objects seems very wasteful. Is there any way that objects can share those methods?

Yes, there is: you can move the methods to the constructor’s prototype. But in order to understand how, we need to go over prototypes and inheritance in JavaScript.

Advertisements

About Karl

I live in the Boston area, and am currently studying for a BS in Computer Science at UMass Boston. I graduated with honors with an AS in Computer Science (Transfer Option) from BHCC, acquiring a certificate in OOP along the way. I also perform experimental electronic music as Karlheinz.
This entry was posted in JavaScript, Programming and tagged . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s