LooselyTyped

(map blog thoughts)

Aug 22, 2012 - JavaScript

On Prototypal Inheritance - Part II

In the first installment of this series, we discussed objects and functions in JavaScript. In this second, and final, installment in this series, we will go a bit further and see how functions are used as “instance factories” or constructors to create objects. We will see how we can use these “constructors” to not only instantiate new instances, but also endow new objects with a predefined set of properties applicable to that “class” of objects (much like Java classes). Finally, we will put it all together to build our own hierarchy. We will also see some potential potholes and how to avoid them in your code.

This is an article I wrote for NFJS, The Magazine’s May, 2012 issue. This is a 2-part series, this being the second one. You can find the first one here.

In our previous discussion, we learned about JavaScript objects and that they have a few magical properties adorned upon them, specifically the constructor property and the __proto__ property. We also noted that all objects (except Object.prototype) participate in a hierarchy – by having their __proto__ property point (directly, or indirectly) to Object.prototype.

We also learned that JavaScript functions are objects themselves and have an additional property called prototype, which points to a plain old JavaScript object. This prototype object, just like any other JavaScript object, has a constructor property that points back to the function itself and it’s __proto__ property points to Object.prototype.

Before proceeding, I encourage you to fire up Google Chrome’s Console (or Firebug’s console) so that you can experiment with the code (See Part I to see how you can do this).

Also, I would like to include our last code snippet Listing 1 and its accompanying visualization Figure 1 from Part 1 just for reference purposes – we are going to need them for our discussion.

Listing 1 - Function.prototype
1
2
3
4
5
6
7

function Person(name) {
    // ignore the argument for this listing
}

console.log(Person.prototype); // evaluates to Person { }
console.log(typeof Person.prototype); // evaluates to "object"

Just like we discussed in Part 1, we are defining a function called Person. This function object has a prototype property that points to a simple JavaScript object, referred to as Person.prototype. This prototype has its own __proto__ property, which in turn points to Object.prototype, and a constructor property that points back to the Person function object. This hierarchy is visualized in Figure 1.

Object.prototype visualized Object.prototype visualized

So that was our recap of Part 1. Ready to begin? Let’s go …

The Constructor Invocation Pattern

Let’s say we wanted to create a “class” of Person objects. These objects are to have a name, and should be polite to one another. Listing 2 is how we would declare and use the Person function to achieve this.

Listing 2 - Constructor invocation pattern
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14

function Person(name) {
    this.name = name;
    this.sayHello = function(other) {
        return "Hello " + other.name + "! My name is " + this.name;
    }
}

// Using the 'Person' function as a "constructor"
var brendan = new Person("Brendan");
var douglas = new Person("Douglas");

console.log(brendan.name); // returns "Brendan"
console.log(brendan.sayHello(douglas)); // returns "Hello Douglas! My name is Brendan"

Some subtle, yet important things to note here. Our Person function object does not have an explicit return. Furthermore, within Person we are referring to some object as this. Lastly, we invoke the Person function with the new keyword. So what’s going on here?

JavaScript overloads the role of a function to act as a constructor when invoked with a new – this is called the “Constructor Invocation pattern”. When you do this, a new object pops into existence within the scope of the constructor, which you can refer to as this. Finally, the constructor evaluates to (that is “returns”) this newly created object.

Armed with that information, you can see what’s going on in Listing 2. When we invoke Person with the new keyword, JavaScript creates a new object. This object, which we can get a handle to using the this keyword within the scope of the Person constructor, is then adorned with the name property, and a sayHello method. sayHello can refer to that object’s name using this.name. Finally, Person returns this newly created object, which is assigned to the variable brendan. Essentially, brendan is an “instantiation” of the Person function. Another way to look at Person is to think of it as the “constructor” and the “class” all rolled into one.

I would like to point out that both brendan and douglas are JavaScript objects like any other – they both have __proto__ pointers but with one big difference – this.__proto__ (where this is the newly created object, so either brendan or douglas – See Figure 2) pointer points to Person.prototype, and not Object.prototype. Conceptually after evaluation, Listing 2 looks as shown in Figure 2.

Objects created using the new operator Objects created using the new operator

Compare Figure 2 with Figure 1 and see how we have managed to intercept the __proto__ lookup chain. If we were to introduce sayGoodbye as a method in Person.prototype only brendan and douglas would see that method as part of the method lookup – all other objects that directly (or indirectly) inherit from Object.prototype are not affected! This allows us to define methods that apply only to a specific (in this case Person) “class” of objects. Pretty neat, right?

Let’s take it up another notch. We have the Person function defined, and consequently we get a Person.prototype. But suppose we realize we need to model Mammal, from which Person (and subsequently) brendan and douglas are to inherit from. How do we go about doing this? Think about this for a few minutes before taking a peek at Listing 3 (Hint: You have to figure out a way to make Person’s prototype point to Mammal’s prototype)

Listing 3 - Creating deeper hierarchies
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11

 // Tack this code on after Listing GAN-2 in your console window
 function Mammal() {}
 Mammal.prototype.nurture = function() {
     return "Care";
 };

 // this is where we rearrange the pointer
 Person.prototype.__proto__ = Mammal.prototype;

 console.log(brendan.nurture); // evaluates to "Care"

Here, Mammal is just another function, and has its own prototype. This prototype object is no different than Person.prototype in that it has a __proto__ property that points to Object.prototype. We then change Person.prototype to point to Mammal.prototype. See Figure 3 to see how this lays itself out (I have left out Object.prototype, but Mammal.prototype.__proto__ points to Object.prototype as indicated by the dashed arrow).

Intercepting the prototype chain Intercepting the prototype chain

The key thing to understand and remember here is that the constructor functions are mere facilitators allowing us to create objects with their __proto__ property set correctly. It’s the objects themselves that intrinsically know who their “prototypes” are and enable function (and property) lookup.

There is another way to set the inheritance chain properly without resorting to what we did in Listing 3. In Part I of this series, we used Object.create to create a new object, but we passed null as an argument. Now that we know how we can use prototypes to enrich the inheritance chain, we will see how to use it. This argument, if supplied, tells JavaScript what the newly created object’s prototype should be. Consider Listing 4 to see how you can use this.

Listing 4 - Using `Object.create` with a prototype
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15

var person = {
    sayHello: function(other) {
        return "Hello " + other.name + "! My name is " + this.name;
    }
};

// here 'person' becomes the 'prototype' for 'brendan'
var brendan = Object.create(person);
brendan.name = "Brendan";

var douglas = Object.create(person);
douglas.name = "Douglas";

brendan.sayHello(douglas); // evaluates to "Hello Douglas! My name is Brendan"

We create a person object that happens to have a sayHello method. We then use this object (Note: Not a function) as an argument to Object.create. Fundamentally, this is the same as Listing 2. The newly created person object serves as brendan’s __proto__ and everything works just as we saw earlier. This just gives us another way to correctly set the prototype chain up of any object.

Putting It To Good Use

Let’s consider two distinct problems and see if we can apply our new found knowledge to solve them. In functional programming, the map function is amongst the most used functions, not only in and of itself, but also as a building block for other higher-order functions. map allows you to apply a function to every element in a collection, thereby transforming each element in the collection, and returns a new collection with the transformed elements. Needless to say, the returned collection has the same size as the one supplied to map. We do this all the time in our Java code, albeit in an iterative fashion. Consider the Java code listed in Listing 5.

Listing 5 - Java map implementation
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12

List<String> names = new ArrayList<String>(3) { {
    add("brendan");
    add("douglas");
    add("john");
} };
List<String> transformedNames = new ArrayList<String>(names.size());

// perform the map
for(String name: names) {
    transformedNames.add(name.toUpperCase());
}

As you can see from Listing 5, we apply the toUpperCase method to every element in the names list and add it to transformedNames. After this code executes, transformedNames will contain exactly three names, all uppercase.

If we were to do this in JavaScript, one approach would be to do as shown in Listing 6.

Listing 6 - Naive JavaScript map implementation
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14

 function map(coll, f) {
     var ret = [];
     for(var i = 0; i < coll.length; i++) {
         ret.push(f(coll[i]));
     }
     return ret;
 }

 // just wrap toUpperCase. You can use apply instead
 // takes a single arg and uppercases it
 function myToUpperCase(str) { return str.toUpperCase(); }

 map(["brendan", "douglas", "john"], myToUpperCase); // return ["BRENDAN", "DOUGLAS", "JOHN"]

Notice that our map function takes another function as its argument, and for each element calls f passing it the nth element of the array and pushes it on to the return array.

If you were to deliberate on this for a moment, it does seem a little smelly. The fact that map has to iterate over the collection seems like feature envy. What if we could have a map method on Array that would accept the transforming function and we could invoke that on any array? That would get rid of the smell. Think about what we discussed and see if you can figure out how to pull that off (before taking a look at Listing 7).

Listing 7 - map implementation using prototype
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12

Array.prototype.map = function(f) {
    var ret = [];
    for(var i = 0; i < this.length; i++) {
        ret.push(f(this[i]));
    }
    return ret;
}

function myToUpperCase(str) { return str.toUpperCase(); }

["brendan", "douglas", "john"].map(myToUpperCase); // return ["BRENDAN", "DOUGLAS", "JOHN"]

We know that when we invoke a method on any object, JavaScript will go through the prototype chain until it finds the method or reaches Object.prototype and bails. All we have to do is get a handle to the __proto__ object of Array, or alternatively ask the Array function for its prototype (which is what we are doing in Listing 7) and tack on the map method. Done! Now, all arrays are blessed with a map method. Note that within the for loop in Listing 7, we refer to the array itself as this – since JavaScript is invoking the map method on an instance of an Array.

Consider another scenario. Let’s say that you wanted to keep tabs on how many Person objects were created during the execution of a program. The way we would do this in Java would be to create a static variable – essentially a variable that is the same across all instances of a class and increment it every time the Person constructor was invoked. How can we do that in JavaScript? Well, we know we have constructor functions that would be invoked with the new keyword, so that would be a good place to increment the counter. But where do we store the variable itself? Doing a this.counter++ won’t work because this within the context of a constructor function refers to the newly created object, making counter an instance variable.

But we also know that functions themselves are objects and can have properties of their own. Can we somehow make use of that? Take a look at Listing 8.

Listing 8 - Implementing static variables
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17

function Person(name) {
    // equivalent to saying Person.counter
    // but more idiomatic
    this.constructor.counter++;
    this.name = name;
}

// init 'static' variable
Person.counter = 0;

brendan = new Person("Brendan");
douglas = new Person("Douglas");

console.log(Person.counter); // returns 2
// alternatively
console.log(brendan.constructor.counter); // also returns 2

If we were to glance back at Figure 3 you will notice that Person.prototype has a constructor property that points back to the its function (Person in this case). Within the context of the constructor function, this is the newly created object, which has its __proto__ property set to Person.prototype. When we ask this (for e.g brendan) for its constructor property, JavaScript looks within the newly created object and does not find it. So it does what we expect it to do – follow the __proto__ property up to Person.prototype which does have it, and hands us back a pointer to the Person function. We then ask it for its counter property (which we have initialized to 0) and increment it. Figure 4 illustrates the state of the system after Listing 8 finishes execution (note that I am not showing Object only to avoid clutter – that hierarchy remains the same in previous illustrations).

Intercepting the prototype chain Intercepting the prototype chain

Of course, we could have just said Person.counter and get the same desired effect, but there might be times when you don’t know the constructor function of an object, so having the constructor property can prove to be really handy.

Words of Caution

Before we conclude this article, I would like to emphasize a few key points. Although __proto__ is a handy property for testing and illustrative purposes (in FireFox and Chrome), by no means should you rely on using (or even assume the existence of) this property in production code. The idiomatic way to getting the prototype of any object is to use the getPrototypeOf method supplied on Object (e.g. Object.getPrototypeOf(brendan)).

We have been naming our constructor functions (like Person and Mammal) with a capital “P” (and “M”) vs. lowercase letters as is the norm for function names in JavaScript. The reason for this is to highlight the fact that they are, in fact, constructors, and should be invoked with the new keyword. Not doing so will result in bad things happening. Constructor functions, as we noted earlier, do not have an explicit “return”, and often refer to this in their function bodies. What does it mean if we were to invoke a constructor function without the new keyword? Let’s take a quick look in Listing 9.

Listing 9 - Calling a constructor function improperly
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14

 function BadlyInvoked(villianiousArg) {
     this.villianiousProperty = villianiousArg;
     this.villianiousFunction = function() {
         return "Muhhhaahaa!";
     }
 }

 var villian = BadlyInvoked("The Joker");
 console.log(villian);  // evaluates to undefined

 // global domination
 console.log(villianiousProperty); // no object context
 console.log(villianiousFunction()); // nor here

Notice that you get no errors whatsoever. JavaScript happily chugs along executing the code, but villian evaluates to undefined. This is because BadlyInvoked does not return anything (and by default, JavaScript returns undefined). Furthermore, you can get to villianiousProperty and villianousFunction without a reference to villian. What happened was upon invocation, BadlyInvoked, did not create a new object, rather it acted as any other function would (remember that if you use the ‘Function Invocation’ pattern, that is invoke a function as a standalone, this is implicitly the “global object”). Therefore, this refers to the global object, which in the browser environment happens to be the window object. We just accidentally introduced two new properties on the window object. If these had been named anything less sinister (e.g. name) you would have just clobbered the global name property! Not to mention that your code will begin to throw all kinds of errors if you attempt to use villian in any way, because it is undefined!

Naming constructor functions with capital letters is idiomatic JavaScript, and the preferred convention as a way to alert fellow developers that this function should be invoked with the new keyword.

Conclusion

Phew! We have reached the end of our whirlwind tour inside JavaScript’s inheritance strategy and implementation. Although some of this may seem a little overwhelming, and perhaps even a tad confusing, hopefully I have given you a clear guide to a better “understanding” of the language and implementing your own inheritance hierarchies within JavaScript.

JavaScript is truly a powerful language. Couple prototypal inheritance with JavaScript’s dynamic nature (adding, removing and changing behavior at runtime), and you are one step closer to unleashing the power to write idiomatic, clean and most importantly, re-usable code within your applications.