LooselyTyped

(map blog thoughts)

Aug 18, 2012 - JavaScript

On Prototypal Inheritance

Douglas Crockford refers to JavaScript as “Lisp in C’s Clothing” which gives us an inkling to it’s true power. Unfortunately JavaScript, a language that started with a rushed schedule to production and a specification that was buffeted with strong political winds at it’s inception, has often been “misunderstood”. Despite it’s unfortunate beginnings, amidst the stormy waters laden with many a pitfall like global variables, lie a few pearls of wisdom, of which one is prototypal inheritance. In this 2-series article we will take a deep dive into JavaScript’s prototypal nature - we will see how it works, and more importantly how we, as JavaScript developers can leverage it. We will take it a step further to see how we can develop our own hierarchies to model our code, allowing for better reuse.

This is an article I wrote for NFJS, The Magazine’s April, 2012 issue. This is a 2-part series, this being the first one - I will post the second one soon. Stay tuned!

Gone are the days when we, as developers could get away with one-off scripts to power our web pages. With the advent of rich, and highly interactive web applications, more and more “core” logic has shifted to the client making JavaScript a first class language within our code-base, and warranting such treatment. Developers are constantly looking to better model their code to reflect real world scenarios, in which inheritance plays an important role. JavaScript does provides you the ability to create rich and deep hierarchies, but does so in a fashion that is not immediately obvious to those coming from a language like Java. To better understand how we can use this valuable feature, we will need to dig past the surface, and examine how JavaScript uses objects, and functions in unison to make this happen.

I highly recommend that you play along with the code as you read this, but you will need a runtime. I suggest you use Google Chrome since it comes bundled with a JavaScript console. Just open up a new tab, right-click anywhere on the page, and select “Inspect Element”. A small window should pop open at the bottom of the page, with it’s own toolbar. The last item on the tool bar is called “Console” - Clicking that will bring you in to the JavaScript console. Another suggestion is to click the icon at the bottom-left of the JavaScript console (The tooltip says “Undock into a seperate window.") - This detaches the Code Inspector from the main window and should give you much more real estate to play with^1 .

Ready? Let’s go find us some inheritance …

Objects

Fundamentally, JavaScript is object-oriented. To those familiar with JavaScript this should come as no surprise. JavaScript comes bundled with a few “global” objects, such as Array, Boolean, Date, String and Object. Instances of these are adorned with certain properties, and behaviors, such as [].length (which is the length of an array), or "javascript".toUpperCase() (which returns "JAVASCRIPT"). There is a subtle, yet important distinction here that I must highlight, and that will be relevant to our on-going discussion. [].length is merely looking up the value of a property in the array, much like you would look up a public variable on an object in Java. On the other hand, "javascript".toUpperCase() is invoking a method on the String instance. This pattern of invocation is referred to as the “Method Invocation Pattern”, in that you are invoking a function as a method of an object^2 .

There is another way to invoke a function, as shown in Listing 1

Listing 1 - Function invocation pattern
1
2
3
4
5
6

function sayHelloTo(name) {
    return "Hello " + name + "!";
}

console.log(sayHelloTo("Brendan")); // evaluates to "Hello Brendan!"

This is called the “Function Invocation” pattern because it seems that you are invoking a stand-alone function. This is not entirely correct - rather the function is attached to the “global” object, which in the case of your browser is the window object.

Creating your own objects

JavaScript allows you to create your own objects, and offers several ways to do so, each offering something subtly different. The easiest way to create an object is to use the literal syntax - {}. You can then attach properties and methods to this object, and you can look these properties up, or invoke these methods just like you would any JavaScript supplied object. Let’s take a look in Listing 2

Listing 2 - Adorning objects
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11

 var myObj = {};

 myObj.name = "Some Object";
 myObj.sayHello = function(name) {
     return "Hello " + name + "!";
 };

 // try it out
 console.log(myObj.name); // evaluates to "Some Object"
 console.log(myObj.sayHello("Brendan")); // evaluates to "Hello Brendan!"

You can declare an object, and all the properties and methods in one fell swoop, as shown in Listing 3

Listing 3 - Adorning objects in one step
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11

var myObj = {
    name : "Some Object", // NOTE the : and the ',' at the end
    sayHello : function(name) {
        return "Hello " + name + "!";
    }
};

// try it out ... again
console.log(myObj.name); // evaluates to "Some Object"
console.log(myObj.sayHello("Brendan")); // evaluates to "Hello Brendan!"

Notice that instead of = signs we use :, and we separate the property definitions using commas as delimiters.

There is another way to define your own object, and that is to use the create method defined on Object. This method takes an argument, the meaning of which we will see in Part II of this series, but for now a null will suffice^3 . Let’s take a look (Listing 4)

Listing 4 - Using Object.create
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11

var myObj = Object.create(null);

myObj.name = "Some Object";
myObj.sayHello = function(name) {
    return "Hello " + name + "!";
};

// try it out
console.log(myObj.name); // returns "Some Object"
console.log(myObj.sayHello("Brendan")); // returns "Hello Brendan!"

Now that we know how to create our own objects, it should be noted that even plain vanilla objects that you create, say with the literal {} syntax, have a few properties and functions magically defined on them. See Listing 5.

Listing 5 - Viewing hidden properties on objects
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13

 var obj = {};

 console.log(obj.constructor); // returns function Object()
 console.log(obj.toString()); // returns [object Object]

 console.log(obj.nonExistentProperty); // returns undefined

 try {
     console.log(obj.nonExistingMethod());
 } catch (e) {
     console.log("Oops! " + e);
 }

As you can see, somehow our obj has a constructor property and a toString function. Just to prove they are the real deal, I invoked the nonExistingProperty property (which returns undefined) and invoked a nonExistingMethod that simply blows up! Where did the toString property come from? To answer that, add one more line to the script you ran in Listing 5, as shown in Listing 6

Listing 6 - Seeing the __proto__ object
1
2

console.log(obj.__proto__);

Within Chrome, the final line should show look like the screenshot I have captured in Figure 1 (Unfortunately there isn’t a way to show the properties of the object within Firefox - All you will see is Object { ... })

Figure 1 - Object.prototype Figure 1 - Object.prototype

What just happened here, and what is that Object being shown in the console? Well, let’s take it a step at a time. obj.__proto__ is (in our example) equivalent to {}.__proto__. Essentially, we are asking our object for its __proto__ object. You see, every object in JavaScript has a “prototype” - This “prototype”, is just that - an object that acts as the template for any new object. This is where the “prototypal” in “prototypal inheritance” comes from - rather than having classes, we simply “clone” existing objects to allow for behavior reuse and inheritance.

This is very different from the class based inheritance many of us are used to in languages like Java. Rather than have two completely different animals - classes and objects like you do in Java (Yes, although classes are objects at runtime you have to admit they have special powers :D), within JavaScript you have only objects. Objects point to other objects and share behavior!

The relationship between our obj from Listing 5 and it’s __proto__ is illustrated in Figure 2

Figure 2 - {}.__proto__ Figure 2 - {}.__proto__

Notice that I have marked our obj’s __proto__ as Object.prototype. The reason for this will become clear after we finish the section on Functions, but from now on, I will refer to it as just that - Object.prototype.

Perhaps you see how method look up works in JavaScript now. When you asked for obj.toString(), JavaScript looked in our newly created object to see if it had a toString function. Needless to say, it didn’t find it, so then JavaScript follows the __proto__ pointer up to the Object which does have a toString! So JavaScript merely calls that function and returns. This is also the same reason why nonExistentProperty and nonExistentMethod both failed - neither our object nor it’s __proto__ have any such properties. Furthermore, Object.prototype does not have a __proto__ property - so this is the end of the line for the lookup chain.

Now that you know this, can you think of a way to write a custom toString method for our newly created obj object? It’s not that much different from Java. See Listing 7

Listing 7 - Adding a instance toString method
 1
 2
 3
 4
 5
 6
 7
 8
 9
10

 // declaring a new object because it's convenient
 // you can use the code in Listing GAN-5 and Listing GAN-6 if you like
 var obj = {};

 obj.toString = function() {
     return "I am a newly created object!";
 }

 console.log(obj.toString()); // evaluates to "I am a newly created object!"

What did we just do? We introduced a new property in our object, namely toString. Now when we ask our obj to evaluate toString JavaScript does not have to go far - it merely executes the first found implementation of the function, which happens to be the one owned by our newly created object. To see how this works, see Figure 3

Figure 3 - instance toString implementation Figure 3 - instance toString implementation

Notice that I have merely stricken out the toString in Object.prototype and not removed it. By putting a newer definition in obj you don’t wipe out the one in Object, you merely shadow it. Furthermore, any new objects that are created without a toString implementation still use the one in Object.prototype. This is no different than inheritance you might be used to in Java-land. The top level (Java) Object class offers a default implementation of toString, and sub-classes can override it to suit their needs. The only difference being that in JavaScript there is no class construct - rather you deal with objects only.

The discussion so far works out fabulously if you need only one object to work with - you can add as many custom methods on to this object as you need and be on your merry way. But classes (like those in Java), and inheritance in general buys us a lot more than that - the ability to have a way to define certain functions and properties for a class of objects in one place, and have all “instances” automatically be adorned with certain behavior.

What if we wanted all of our objects to be able to greet other objects? If we were to put a sayHello method in Object.prototype, then any object created with it’s __proto__ property pointing to Object.prototype will automatically inherit that method. Let’s give it a whirl in Listing 8

Listing 8 - Global sayHello method
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15

 // declaring a new object because it's convenient
 // you can use the code in Listing GAN-5 if you like
 var obj = {};

 obj.__proto__.sayHello = function(name) {
     return "Hello " + name + "!";
 }

 console.log(obj.sayHello("Brendan")); // evaluates to "Hello Brendan!"

 // create another object
 var anotherObj = {};

console.log(anotherObj.sayHello("Douglas")); // evaluates to "Hello Douglas!"

When we say obj.__proto__ we are getting a reference to the Object.prototype object. We then tack on sayHello on to it, and then create anotherObject (which automatically inherits from Object.prototype). This is illustrated in Figure 4

Figure GAN-4 - Global sayHello implementation visualized Figure GAN-4 - Global sayHello implementation visualized

Problem solved? Not quite. Most of us would be frowning right about now. By introducing the sayHello in the Object.prototype every object has the ability to speak! This includes the objects that JavaScript ships with. Try [].sayHello("John") in your console. Needless to say, this is a sledge-hammer approach to inheritance. No Java programmer worth his salt would (if they could) put this method in Object.

So what we need is a way to introduce newly created objects with their own “prototype” object - one that adorns them with specific behaviors that are applicable to any object of that class or genre. How do we do that?

That is the question we are here to answer. Before we go there, we need to talk at about functions in JavaScript^4 .

Functions

JavaScript is a functional programming language, in that functions are first-class citizens. This is a departure from languages like Java where functions, or rather methods are underlings to the objects to which they belong. What this means is that functions are like any other datatype in JavaScript - Just as you would assign a String to a variable or return a Number from a function (or a method), you can do the same with functions. You can assign a function to a variable (and you saw an example of this in Listing 2 where we assigned sayHello to a function) and you can pass functions as arguments to other functions. You can even have functions create other functions a.k.a higher-order functions. Let’s explore some of these concepts really quickly in Listing 9

Listing 9 - Functional programming
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

// extremely contrived example but math operators in
// JS are baked into the language. This is just a simple
// wrapper
// This is NOT idiomatic.
function add(a, b) {
    return a + b;
}

var somePointerToAdd = add; // have a variable point to the 'add' function
// You can invoke add in multiple ways
console.log(add(2, 3)); // returns 5
console.log(somePointerToAdd(2, 3)); // returns 5
console.log(somePointerToAdd == add); // prove they are the same - returns true
// This function creates an "incrementor" function and returns.
// Given an arg 'n' it returns a NEW function
// that takes just one argument and upon invocation returns 'add(n, arg)'
function incrementBy(n) {
    return function(arg) { return add(n, arg) };
}

// essentially returns function(arg) { return add(3, arg); }
var incrementor = incrementBy(3);
// invoke function(arg) { return add(3, arg); } giving it 5 as an arg, returns 8
console.log(incrementor(5));

Note that incrementor is a pointer to the newly created function that gets returned by incrementBy(3). This is no different than saying var x = "Brendan".

This is a powerful construct, and makes JavaScript an incredibly powerful language, but as is always the case with JavaScript, there is more to it than meets the eye. JavaScript functions, are in fact, full blown objects in and of themselves! If you were to glance at the JavaScript documentation you will see that there is a ‘Function’ object, it succinctly says

Every function in JavaScript is actually a Function object.

Our earlier discussion about objects, properties, and methods applies to functions as well. That is, functions can have properties and methods assigned to them! Whenever you declare a new function in JavaScript, a new Function object is created, and much like other objects (like we saw in Listing 5) are blessed auto-magically with a few properties, of which, constructor and prototype being the ones relevant to our discussion at hand. You can get a handle to the function object simply by using it’s name, like Person. (I noted in 2 that you could do "javascript".toUpperCase, without the parentheses - that is essentially giving you back a handle to the toUpperCase function). See Listing 10^5

Listing 10 - 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"

Notice that the prototype property evaluates to an object, which happens to be just another plain vanilla JavaScript object. See Figure 5 for a (simplistic) illustration on how this works.

Figure 5 - Function.prototype visualized Figure 5 - Function.prototype visualized

The object on the left is the Person function object, and the object to the right is it’s “prototype”, which happens to be a plain JavaScript object. Two things of note here - Functions get a special “prototype” property (different from the __proto__ property we saw earlier), and the functions prototype object (which happens to be a simple JavaScript object) gets a __proto__ property just like we saw in the earlier section. The prototype object’s constructor property points back to the function object itself. The way you refer to a function’s (in this case Person) prototype is just like you would any other property - <name_of_object>.<name_of_property> - so to reference Person’s prototype we say Person.prototype.

If this looks familiar, it’s because it is. Earlier (in Figure 2) I marked our obj’s __proto__ as Object.prototype! Looking at Listing 10 what can we infer? Simply put, there is a function object called Object, in that there is a function declared with the name Object (like so function Object() { ... }), for which JavaScript creates a (Function) object, and this object points to another (plain vanilla JavaScript) object that happens to be it’s “prototype”. See Figure 6 to get an idea of how this lays itself out.

Figure 6 - Object.prototype visualized Figure 6 - Object.prototype visualized

To summarize, functions in JavaScript are just objects, albeit a little special because they all have a prototype property. This prototype property is just another object, which like any other object that you create, is part of an inheritance chain with Object.prototype at the end.

Now that we know all this, how can we use this to properly adorn our “person” objects with a predefined set of behaviors? Well, we still have one more hurdle to surmount before we get there, but unfortunately, we have reached the end of our journey for this installment. In part 2, we will first see how functions can be used as constructors, and use this to build our own inheritance hierarchies in JavaScript.

A minor digression

So far in this article, I have used the word “object”, and “instance”. This can be a contentious issue in JavaScript’s terminology due to the fact that JavaScript does not have the traditional notion of a “class” - so what exactly constitutes an “instance”? Well traditionally, in languages like Java, an instance is an object. But in JavaScript, as we have noted, constructs like the function Object, and our own Person (which as we will see in our next installment are the conduits to creating “instances”) are also objects.

One way to define an “instance” is like so - “instances” are created when we use the new keyword along-with a function name. Consider var myString = new String("Douglas") - in this case, myString is an “instance” of String. We should note that sometimes this is not so obvious. IN Listing 2 we used the literal syntax ({}) for creating a new object - Under the covers this (roughly) translates to new Object() - so once again, we have created an “instance” of Object. Other examples include [1, 2, 3] (which happens to be an Array) instance, and /+d/ which is an instance of RegExp.

The thing to take away here is that in a language like JavaScript, the distinction between “instances” and “objects” boils down to being borderline academic. As long as you understand how to use objects, and (in Part 2) how functions can be used as “instance factories”, in my opinion there is no reason to fret over the terminology.

Conclusion

JavaScript is inherently an object-oriented language. More so than many languages that we may have encountered, in that in JavaScript functions are also objects, albeit with a difference. Objects are adorned with properties, including a magical property called __proto__, which allows the object to participate in an inheritance, and look-up chain. Functions, on the other hand, are a tad special, and have an additional property called prototype and we will see how we can use this to build our own hierarchies in Part 2.


1. You can also use FireFox along with Firebug. Once you have that installed, create a new HTML file with the contents <!DOCTYPE html><title>On Protoypal Inheritance</title> and save it anywhere on your computer. Then open the newly created file in Firefox, right-click anywhere on the page, and select “Inspect Element with Firebug”. This too has a menu bar of it’s own that has a “Console” option. Clicking that will bring you into the JavaScript console. If you are on a Mac, Safari (Version 5.1.3) also has a console similar to that of Chrome’s.

2. You could even do "javascript".toUpperCase (note that there are no parenthesis following the method name) but this does something very different, and which hopefully will become more apparent as we go forward.

3. You can create the object, along with certain properties and methods in one fell swoop like we did in Listing 2 but I left that out for two reasons - It does not help our discussion here, and the syntax can be a tad confusing. For details see this link.

4. I realize that this section may have left you with more questions than answers, but I promise that it will all become clear soon.

5. I realize that the function has a name starting with a capital “P” vs. a lowercase as is usually the case. I can tell you that there’s a good reason :)