JavaScript and inheritance

JavaScript has a complicated history. The name itself seems to indicate a relationship to Java, when in fact, the two languages share little in common except for a common syntax relationship by way of C. Add to this the myriad of browser incompatibilities and numerous examples of bad usage, and you have what is perhaps the world’s least understood popular programming language. (I had to add the ‘popular’ qualifier, since I am sure there are some esoteric languages out there that only a handful of people know)

This is why inheritance in JavaScript is probably one of the least understood concepts. While languages like Java have well-defined constructs for inheritance, the topic is of less importance with JavaScript. In many situations, you’ll never have to deal with these aspects when programming in JavaScript, simply because it isn’t required for a lot of client side scripts. However, for larger-scale web applications, applying object-oriented principles to your code may make it easier to design, improve and maintain.

There have been many articles written about inheritance in JavaScript and how it can and should be done. You really don’t need to read mine to gain an understanding. Rather, I’m just going to write about what I’ve learned, the process I went through and the experience I’ve gained along the way.

It’s all new(s) to me

If you come from a Java background, you’ll be no stranger to the new keyword. Using it allows you to instantiate a new instance of an object from its class by calling its constructor. The keyword also makes a lot of sense, since you’re creating a ‘new’ object.

JavaScript also has a new keyword, but it doesn’t do quite the same thing as its Java counterpart, though at first the effects might seem similar. This is one of the main reasons why JavaScript inheritance tends to be poorly understood.

Consider the following example.

function Foo(name)
{
  this.name = name;
}

var fooObject = new Foo('I am foo');

If you’re familiar with Java or JavaScript, this example is fairly straightforward. In the prototype-based JavaScript, functions can serve as object constructors in somewhat the same manner as a constructor in Java. However, Foo in the above example is not a class, since classes do not exist in JavaScript. So, if Foo is not a class, what exactly happens when the statement var fooObject = new Foo('I am foo') is executed?

Taking a step back

Before we dive into the details, I’ll explain the concepts of a prototype-based language as it applies to JavaScript. I mentioned above that JavaScript does not use classes like Java does. This basically means that new objects are not created from instantiation of classes, but rather inherit from existing objects. Thus, there is no “class hierarchy” but rather just an object hierarchy.

In JavaScript, all objects are descended from the built-in Object type. This is similar to how all Java classes implicitly have the Object class as a superclass. In JavaScript, instead of extending classes, you can inherit by manipulating the prototype property on a type; that is, the prototype property on the function you are using to create an object. Let’s see some code to straighten things out.

function Foo(name)
{
  this.name = name;
}
Foo.prototype.getName = function()
{
  alert(this.name);
}

var fooObject = new Foo('I am foo');
fooObject.getName(); // Will alert with 'I am foo'

This example is identical to the first one, except for the lines that are emphasized. Here, I’ve set the getName property on the prototype property of Foo equal to a reference to a Function object. This is effectively the same as defining a method for a class, since any object created from that type can call the method getName() on itself to return the proper value. But what exactly is happening, and what’s the deal with the prototype property?

More new(s)

In JavaScript, the new keyword actually accomplishes a few things. When you execute an expression such as var fooObject = new Foo('I am foo'), here’s exactly what happens.

  1. First, a new generic object is created. This object is the same as if you created the object using the statement new Object(), using JavaScript’s built in Object type.
  2. The constructor function, that is, the function Foo(), is then called with the this keyword set to reference the newly-created object. The parameters supplied are also passed to the constructor function, in this case, the string “I am foo”. If you’re familiar with context, this is equivalent to:
    var fooObject = new Object();
    Foo.call(fooObject, 'I am foo');

    Thus, the code in Foo() sets a property called name equal to the supplied string. Up to this point, things are the same as if you had created a new object and then manually set the name property yourself. The next step is where things change.

  3. The last step is where inheritance takes effect. The constructor function, in addition to executing the specified code above, also sets an internal property called __proto__ equal to the value of Foo.prototype. This is how the new object inherits from the old one.

    When you call a property on fooObject now, JavaScript will first check to see if the object has a local value for it. In this case, the only local property is name. (Besides the internal and implicitly set __proto__ property) However, if it does not exist locally, it will check to see if the property exists under the object referenced by the __proto__ property. In this case, the getName() method exists under here.

Where things get confusing is because of how the new keyword is used. Perhaps the designers of JavaScript wanted to use a keyword familiar to Java programmers so as to ease the transition to a new language that sounded so similar. While it accomplishes a similar goal and for the most part you can consider the action to be almost the same, the use of the new keyword conceals the true meaning of prototype-based inheritance in JavaScript. This ends up causing more confusion when you start digging into code.

We’re all the same

Suppose you created multiple objects from the Foo() constructor, called fooObject1, fooObject2 and fooObject3, In one fell swoop, you could add a new method to all of these objects without having to recreate them. This is because of the prototype property. Because each object contains a reference to Foo.prototype, adding a new method here will allow all objects access to it. For example:

Foo.prototype.yellName = function()
{
  alert(this.name.toUpperCase());
}
var fooObject3 = new Foo('I am Foo 3!');
fooObject3.yellName(); // alerts 'I AM FOO 3!'

This adds another method to all Foo-constructed objects allowing them to “yell” their names.

Extending Types

I mentioned inheritance above but with just one type definition, the principles weren’t too clear. Suppose we decided to extend our Foo “class” – how exactly would this work? First, you need to define the child type and then set its prototype value to a new object of the parent type. An example:

function FooChild(childName)
{
  Foo.call(this, 'I am a child of Foo and my name is ' + childName);
}
FooChild.prototype = new Foo('');

var fooChildObject = new FooChild('Barbar');
fooChildObject.getName(); // Will alert with 'I am a child of Foo and my name is Barbar'

Let’s break down what’s going on here.

  1. First, we define a new constructor called FooChild. In it, we call the parent constructor function with the context set to the current object. This allows the name property to be set on the object during creation since that’s what the parent does.
  2. Then, we set the prototype property equal to a new object that’s an instance of Foo. This is what allows all of the child objects to have access to the parent’s properties, such as the getName() method. Coming from the Java world, this would be roughly equivalent to the extends keyword, when defining a class that inherits from another.

A few more details

JavaScript provides two special operators for dealing with types and objects. One is called instanceof and the other is typeof. The latter, typeof, is less useful since it only deals with built-in JavaScript types.

The typeof operator returns the current variable’s type, but is limited to predefined types. For example, typeof fooChildObject or typeof fooObject both return a string with the contents of “object”. Thus, differentiating between the two is impossible. More information can be found at the Mozilla Developer Center.

The instanceof operator is more interesting. It takes two arguments and tests whether the first is an instance of the second. (I guess I didn’t need to explain that) For example:

function Foo(name)
{
  this.name = name;
}
Foo.prototype.getName = function()
{
  alert(this.name);
}

function FooChild(childName)
{
  Foo.call(this, 'I am a child of Foo and my name is ' + childName);
}
FooChild.prototype = new Foo('');

var fooObject = new Foo('I am foo');
var fooChildObject = new FooChild('Barbar');

alert(fooChildObject instanceof Foo); // true
alert(fooObject instanceof Foo); // true
alert(fooChildObject instanceof FooChild); // true
alert(fooObject instanceof FooChild); // false;

In the above code, it is clear that fooChildObject is an instance of FooChild, and fooObjectis an instance of Foo. However, fooChildObject is also an instance of Foo, since its type was inherited from it through the prototype property. However, fooObject is not an instance of FooChild since that type is a child of Foo.

I hope I haven’t said “foo” one too many times for you.

More information about instanceof is again available from the excellent Mozilla Developer Center.

Concluding remarks

I hope this has helped you to understand the nature of JavaScript’s built-in inheritance features. I know I found it very convoluted at first, coming from a class-inheritance background. I read everything I could find on the subject, and I believe it’s made me a better JavaScript programmer by understanding some of the “inner workings” of the language. I encourage you to check out some of the references I’ve provided below.

References

  1. Prototypal Inheritance in JavaScript – Douglas Crockford
  2. The Philosophy of JavaScript – Jesse of 20bits
  3. Prototype Inheritance Revisited – Mozilla Developer Center
  4. The Employee Example – Mozilla Developer Center

One Comment »

  1. Hi Peter,

    very nice summary, very clearly explained. Thanks a lot.

    Tom

Comments are now closed for this entry.