Constructor

Alternative ways to create new object instances.



Usage in JavaScript:
high


Fundamentals


The Constructor pattern refers to the process of creating new object instances in JavaScript. There are different ways of doing this and it is important to understand the different options.

If you are coming from a class-based language you're familiar with creating objects by calling a class constructor with the new operator. JavaScript does not support classes but it does have a new operator. Calling new with a constructor function will return a newly created object instance, like this:

var obj = new Object();           // new operator

This creates an empty object which doesn't do very much. To create more interesting and useful objects we need to add properties and methods. JavaScript is a dynamic language that allows us to create an empty object and subsequently add object members by using the dot operator:

var obj = new Object();
obj.name = "Anthony Miller";
obj.hello = function () { alert("hello"); }

Alternatively we can use the [] operator.

var obj = new Object();
obj["name"] = "Anthony Miller";
obj["hello"] = function () { alert("hello"); };

For objects with many properties this can become rather tedious. A more compact way of doing this is with object literals which are object definitions surrounded by curly braces. Let's start off with a basic example. Here we create an empty person object:

var person = {};      // object literal notation

Next we'll create a more interesting object with a property and a method in a single statement:

var person = {
   name: "Anthony Miller",
   say: function () { alert(this.name); }
};

person.say();       // => Anthony Miller

Run

This object has two members: a property called name and a method called say (by the way: a method is a function that is part of an object). The say method displays the person's name.

Object literal notation is frequently used by JavaScript developers. However, as used above, the object literal is not reusable. Constructor functions were designed to be reusable and are discussed next.

The Object constructor function is native to JavaScript and allows you to create empty objects. It is rarely used, but you can create custom constructor functions that are used extensively in JavaScript. Here is an example:

function Person() {
    this.name = "Nelly Jones";
    this.say = function () { alert(this.name); }; 
}

var person = new Person();
person.say();               // => Nelly Jones

Run

This creates a person object with hardcoded property values. A more flexible and reusable approach is to create a constructor function that takes an argument with which the name is initialized:

function Person(name) {
    this.name = name;
    this.say = function () { alert(this.name); }; 
}

var anthony = new Person("Anthony Miller");
var celeste = new Person("Celeste Diaz");

anthony.say();               // => Anthony Miller
celeste.say();               // => Celeste Diaz

Run

The this keyword in the function body is bound to the object that is being created and is called the context of the function. We now have a truly reusable constructor function which allows us to create many new instances without much effort.

Alternatively, we can create an anonymous constructor function and assign it to a variable, like so:

var Person = function (name) {
    this.name = name;
    this.say = function () { alert(this.name); }; 
}
var anthony = new Person("Anthony Miller");
var celeste = new Person("Celeste Diaz");

anthony.say();               // => Anthony Miller
celeste.say();               // => Celeste Diaz
Run

The function does not have a name (it is anonymous) and is assigned to a variable as if it were a primitive value or object type. This is not far off, because, in fact, functions are true objects. They come with properties and methods just like objects. This is why they are referred to as function objects.

Whether you use a named function or an anonymous function that you assign to a variable makes no difference in how you use it. Either way, you use the new operator followed by the function name or the variable name.

However, there is a slight difference when debugging. Since an anonymous function has no name there is no way for the debugger to reference or search for it. For this reason, some developers prefer named functions over anonymous functions.

By convention the name of a constructor function starts with an uppercase letter. All other functions start with lowercase. This is merely a convention but a very important one. Here is why. Let's say you forget to include the new keyword when creating new persons, like this:

var Person = function (name) {
    this.name = name;
    this.say = function () { alert(this.name) }; 
}

var anthony = Person("Anthony Miller");   // missing new
var celeste = Person("Celeste Diaz");     // missing new

There will be no warning and initially the program seems to run fine, but after a while you start to see errors. What happens when you omit the new keyword is that the this reference does not get bound to the current object but to the global object instead (window in browsers).

JavaScript, being a dynamic language, will happily create the name property and the say function on the global object without warning, but now all persons are starting to overwrite each other's name.

The problem is that these bugs can be very difficult to find. Other than visual inspection (i.e., a developer staring at the code) there is no good way to discover the source of the problem. Having a constructor function with an upper case letter is a useful hint to developers that a new prefix is required.

EcmaScript 5 addresses the problem. When in strict mode ("use strict";) the keyword this will no longer reference the global object. But what if you are not able to use the ES5 standard yet? Fortunately, there is a simple ways to defensively code against forgetting the new prefix:

var Person = function (name) {
    if (!(this instanceof Person)) { 
       return new Person(name); 
    }

    this.name = name;
    this.say = function () {alert(this.name);}; 
}
var anthony = Person("Anthony Miller");    // missing new
var celeste = Person("Celeste Diaz");      // missing new

anthony.say();       // => Anthony Miller
celeste.say();       // => Celeste Diaz

Run

In this example, the constructor function checks if this is of type Person. If it is not, then that means that this was omitted and it will immediately correct the situation by calling the constructor function prefixed with this. The overhead of the if-statement is minimal and it can avoid late night debugging sessions in the office.

Constructor functions implicitly return the object referenced by this. There is no need to include a return statement. However, you can return your own objects if you prefer:

var Person = function (name) {
    var that = {};
    that.name = name; 
    that.say = function () {alert(this.name);}
    return that;
};

Please note: the variable that is not a keyword, just an alternative for this. You can write the above code more succinctly by returning an object literal without the need for a that variable:

var Person = function (name) {
    return {
        name: name,
        say: function () {alert(this.name);}
    };
}

This is a frequently used style as it allows the creation of private variables. Classically trained developers are used to access modifiers: private, protected, and public, but JavaScript does not support these. Fortunately, you can create private variables following this approach:

var Person = function (name) {
    
    var privateName = name;    // private 

    return {
        say: function () { alert(privateName); }
    };
}

var anthony = new Person("Anthony Miller");
var celeste = new Person("Celeste Diaz");

anthony.say();                                 // Anthony Miller
celeste.say();                                 // Celeste Diaz

Run

The incoming name argument is assigned to local variable named privateName. Notice that the say method now displays privateName. Although JavaScript does not natively support private members (or any other access modifier), this variable is truly private and not accessible from anywhere outside the function body.

You may be wondering what the value of privateName will be after the constructor is called, for example, when the say() method displays its value. Rest assured it is the original value when the object was created. The value will be maintained during the lifetime of the object. You can see that this is the case with anthony and celeste.

What is at work here is an important concept in JavaScript called a closure. When instantiating an object with a constructor function the internal values are wrapped into a closure and stay into existence until the object goes out of scope and gets garbage collected.

By the way, argument values are also part of a function's closure. In the above case, the closure maintains the values of two variables: name and privateName. So, if name is part of the closure, then there is no need to assign the argument to a local value; correct? Yes, that is indeed correct. Look at the following code:

var Person = function (name) {
    return {
        say: function () { alert(name); }
    };
}

var anthony = Person("Anthony Miller");
var celeste = Person("Celeste Diaz");

anthony.say();                                 // Anthony Miller
celeste.say();                                 // Celeste Diaz

Run

As you can see this works the same as the prior example that used privateName.

You can also change argument values and they will still be maintained by the closure.

var Person = function (name) {
    return {
        setName: function (n) {name = n;},
        getName: function () {return name;},
        say: function () {alert(name);}
    };
}

var person = Person("Superman");
person.say();                                 // => Superman

person.setName("King Kong");
person.say();                                 // => King Kong
    
Run

Works like a charm.

Building private functions is also a breeze with closures:

var Person = function (name) {
     
    var privateName = name;                          // private 
    var privateLength = function () {                // private
        return privateName.length; 
    };   

    return {
        name: privateName,                           // public
        nameLength: privateLength,                   // public
        say: function () { alert(privateName); }     // public
    };
}

The function privateLength is private. Everything that is returned is public. Notice that a person's public properties and methods have full access to its private variables and functions (and arguments), even beyond the creation stage; again this is courtesy of the closure that was constructed for us.

Rather than returning an object using an object literal we can also return a function (actually a function literal). Just like the object literal the returned function also has full access to any private variable or function in the surrounding constructor function.

var Person = function (name) {
    
    var privateName = name;                                // private
    var privateLength = function () {                      // private
        return privateName.length;                         
    };  

    return function (name) {
        this.name = name,                                  // public
        this.nameLength = privateLength,                   // public
        this.say = function () { alert(privateName); }     // public
    };
}

The constructor functions we've looked at so far have both properties and methods defined in their function body. Each object instance that we create has a full set of properties and methods.

We can limit the memory of each instance by having all instances share their methods. We do this by moving the methods out to the function's prototype. Each instance will have full access to these methods through their prototype properties. Here is the original code with methods in the function body.

function Person(name) {
    this.name = name;
    this.say = function () { alert(this.name); }; 
}

And here is the same with the say method moved to its prototype

function Person(name) {
    this.name = name;
}
Person.prototype.say = function () {
    alert(this.name);
}

var anthony = new Person("Anthony Miller");
var celeste = new Person("Celeste Diaz");

anthony.say();                                 // Anthony Miller
celeste.say();                                 // Celeste Diaz
Run

The prototype method displays the name of the person and is shared by both instances. This shows that the prototype function, although shared, has full access to each objects' properties through this which is bound to the current object.

Following the construction of an object you can have follow-up step called initialization. Essentially, object initialization is a way to complete an object's initialization. Some popular Model-View frameworks use this pattern, notably Backbone and Ember. They let you create new objects by extending their framework objects. Then the framework will call an init or initialize method giving the object the opportunity to complete the initialization process. Here is an example:

function Person() {
    this.name = "";
    this.say = function () { alert(this.name); };

    this.age = 0;
    this.profession = "None";

    this.init = function (options) {                // initializer
        this.name = options.name;
        this.age = options.age;
        this.profession = options.profession;
        this.showAge = function () {
            alert(this.age);
        };
    };
}

var person = new Person();
person.init( {name: "Al", age: 33, profession: "JS Geek"} );    

person.say();                // John
person.showAge();            // 33

Run

This example is a bit contrived but hopefully you get the idea. The init method may accept options that configure the object or it is a place where relationships are established with other objects in the app.



Namespace