JavaScript for the C# Developer Part 7 – Prototypal Inheritance

Previous: JavaScript for the C# Developer Part 6 – Objects

In the previous post you learned that JavaScript has objects but not classes. The post demonstrates the use of a simple factory method to create a closure that contains an object’s private state and an object created via an object literal (http://jsfiddle.net/DougWare/3Z9M6/). I like this technique because it is simple, the way it works is clear, and it isn’t easy to screw up as is the case with constructor functions and the new keyword. However, it has a couple clear disadvantages:

  • There is no direct way to test the object to determine its origin
  • Every object produced by the factory has its own copy its methods and its use of memory is not optimal

For these reasons I only use object literals for occasions when there will only be a small number of instances of the object in question, ideally only one. This is usually the case, but a given system probably has a few objects of which many instances are created. For these objects a different approach is needed. Instead of creating these objects with literals I want to create them from named models that I can reuse and extend as needed. These models are called prototypes.

Class based inheritance versus prototypal inheritance

C# has classes. The structure of a given object instance is defined by its class. C# supports polymorphism via classes; one class inherits from another class and add to, or override, its parent’s definition. In C# all classes share a common ancestor, the Object class.

JavaScript does not have classes. Instead JavaScript objects serve the same role by acting as prototypes. New objects are created by copying existing objects. The existing object acts as a model that defines the new object. JavaScript supports polymorphism because you can modify the new object and use it as the basis of yet more objects. Instead of a class hierarchy, JavaScript has a prototype chain. At the top of the prototype chain is a common ancestor, a function named Object.

When you create an object literal you are inheriting from Object.

Every object but one has a prototype

The only object that doesn’t have a prototype is the top of the prototype chain, Object, just as Object in C# has no base class. The prototype of every object literal is Object. When you try to access a member of an object, JavaScript first checks the object for a member with the specified name. If it doesn’t find it, it checks the prototype, then the prototype’s prototype, and so on until it gets to the top of the prototype chain. If it isn’t found anywhere in the chain, it is undefined.

Confusing naming causes confusion

JavaScript functions have a property named prototype. The prototype property is not the function object instance’s actual prototype and it behaves differently in different browsers. Because of this, if you try to understand how prototypes work by focusing on this property, you may end up like this.


The best detailed explanation I have seen for all this is this article: Constructors considered mildly confusing. I am going to attempt to explain it without spending much time talking about what is going on under the covers and try to make things as simple as possible.

The key thing to remember is that the value of a function’s prototype property is not the function’s prototype – it is the object assigned as the prototype of objects created by the function when the function is a constructor. A function’s prototype property contains an object instance which is applied as the model to all object instances created by the function when the function is used as a constructor function via the new keyword.

Constructor Functions

To review, the previous post taught you that JavaScript includes the keyword new.
When JavaScript sees new in front of a function call the function is a constructor function. JavaScript creates a new empty object instance, executes the constructor, and returns a new object that contains the object as initialized by the constructor. All the constructor must do is use the this keyword to extend the new object instance with the desired properties and methods as follows (http://jsfiddle.net/DougWare/whx3L/).


This example illustrates that the redShirt object and the blueShirt object exist independently of each other and each maintains its own private state.

The problem with this example is that the constructor initializes the object’s members each time it is invoked. Every instance gets its own identical copy of the getColorSize function just as each would if I used an object literal returned by a factory method. This is where the prototype property’s object instance is beneficial.

An example of a constructor that takes advantage of a constructor’s prototype looks like this (http://jsfiddle.net/DougWare/QYpM6/).


In this example, the constructor, Animal, and the object, pig, have no members of their own. This is proven by using the hasOwnProperty function. hasOwnProperty tests to see if an object instance has a property that is part of the instance. If the property is part of the prototype chain, or if the property is undefined hasOwnProperty returns false. When the code invokes identify() it is invoking the function that is attached to the prototype because the instance does not contain a member named identify. The same is true of the name property, but when a new value is assigned to the instance’s name property, JavaScript adds the property to the instance and no longer needs to traverse the prototype chain (http://jsfiddle.net/DougWare/vGvfj/).


The prototype property is assignable and can be any object

In the examples above, Animal.prototype is extended one member at a time. However, because prototype contains an object instance, any object can be a prototype. Therefore, the example can be rewritten as follows (http://jsfiddle.net/DougWare/4DYGW/).


Extending the prototype, Extension methods

By now it should be clear that all instances created from the same constructor point to the same prototype instance. This is the reason that using prototype offers superior performance and memory usage when you have many instances of the same type of object. One implication of this is that changing or extending the prototype instance affects every object on the prototype chain (http://jsfiddle.net/DougWare/VE52D/).


An implication of this is that you can extend all of the built-in classes to add methods just as you can with extension methods in C#. JavaScript coerces the primitive types string and number to objects to allow access to their prototype objects. Douglas Crockford uses this technique to extend Object to create a simple object factory that works for any object instance (http://javascript.crockford.com/prototypal.html). You can see it in action in the next example (http://jsfiddle.net/DougWare/MJaXL/).


Multiple levels of inheritance

It is possible to have multiple levels of inheritance by applying the parent object’s prototype to the constructor function of the child object (http://jsfiddle.net/DougWare/nKYtW/).


I feel compelled to editorialize on this point. You should be suspicious of this sort of thing when you see it in a design. There are times when inheritance of this type is valuable, but in my experience this is uncommon. You should carefully weigh the complexity of this technique against the potential benefit of a simpler design.

Using instanceof and is isPrototypeOf to determine an object’s origin

There are times when you may need to test an object instance to determine its origin. Every object has a constructor property which is an object containing a prototype property. You can’t trust these values and you should not use them! Instead you can use the instanceof comparison operator to identify an object’s constructor. One of the benefits of instanceof is that you can test for any level of the prototype chain (http://jsfiddle.net/DougWare/RDQU2/).


The instanceof operator requires you to have a working reference to the constructor function for the right-hand side of the comparison. You may not have such a reference. As an alternative you can check to see if a given object is the prototype of another object with the isPrototypeOf method (http://jsfiddle.net/DougWare/fzSPm/).


In this example the constructor function is f(), but at the location of the test, f() is inaccessible and out of scope.

Conclusion

If you made it all the way through this post you probably get that using prototypes is much more complex than using object literals as described in the previous post. Limiting your use of this technique is a good idea if your code is to be used or maintained by developers who are likely to be confused by prototypes. If you only have one or two instances of a given object you definitely should not use this technique. If you will have many instances the performance and memory savings prototypal inheritance brings justifies the additional complexity.

This is the second to last post I currently have planned for this series. The final post will be about the very confusing this keyword. If you’ve made it this far, you should have no trouble understanding it!

Next: JavaScript for the C# Developer Part 8 – WTF is this?

Author: Doug Ware