Scott Allen | July 22, 2010
Recently I was watching the 24 Hours of Le Mans –a popular racing event in France. The fastest cars in the race are the Le Mans Prototypes. Although these cars are built by car manufacturers like Audi and Peugeot, they are not cars you’ll see on the streets and highways of your home town. They are built exclusively for high-speed endurance racing.
Manufacturers put an enormous amount of money into researching, engineering, and building these prototype cars, and the engineers are always trying to find an edge. They experiment with alloys, biofuels, brake technologies, tire compounds, and safety features. Over time, some of these experiments are refined and make their way into mainstream production cars. Some of the technology in your car made its first appearance in a racing prototype.
You could say mainstream cars inherit technology from racing prototypes.
Of Objects and Classes
This approach doesn’t scale, however. We want to make sure every point object has an add method. We also want all point objects to share a single implementation of the add function instead of placing an add function into every point object. This is where prototypes come into play.
Moving forward as developers, we will be able to use the Object.getPrototypeOf function instead of the __proto__ property to inspect an object’s prototype reference. At the time of writing, we can use Object.getPrototypeOf in Google Chrome, Firefox, and IE9. More browsers will implement this feature in the future, as it is now part of the ECMAScript standard. We can use the following code to prove that the myArray and point objects we’ve created truly reference two different prototype objects.
For the rest of this article I’ll use __proto__ and Object.getPrototypeOf interchangeably, primarily because __proto__ is easier to look at in diagrams and sentences. Just keep in mind it isn’t standard, and Object.getPrototypeOf is the recommended technique to uncover an object’s prototype.
What Makes Prototypes Special?
We’ve yet to answer the question: where does an array’s push method come from? It turns out the answer is in the prototype object for myArray. Figure 2 is a screenshot of the script debugger in Chrome. We’ve invoked Object.getPrototypeOf for myArray to inspect its prototype object.
Notice the prototype object for myArray includes a number of functions, including the push, pop, and reverse methods we invoked in our opening code sample. So the prototype object is the one holding the push method, but how does this method get invoked through myArray?
Then both arrays will share the same prototype object, and following code evaluates to true:
The next question you might ask is: how do I set prototype references for my custom objects? For example, with the point object we were working with earlier – how can we put the add method into a prototype object and inherit the method from multiple point objects? Before we can answer this question, we’ll need to look at functions.
What we need to focus on is the fact that functions are objects, and because functions are objects then functions themselves can have methods, properties, and reference a prototype object. Let’s discuss the implications of the following code.
Array.__proto__ gives us the prototype for Array – think of this as the object the Array function inherits from.
Array.protoype, on the other hand, is the prototype object for all arrays. That is, it’s the prototype object for array objects like myArray, and it contains the methods all arrays will inherit. We can write some code to prove this fact.
We can also redraw our previous diagram with this new knowledge.
Given what we know, imagine we want to create a new object and make the new object behave like an array. One approach would be to use the following code.
The call method of a function allows you to invoke a function and specify the object to use as the “this” reference inside the function. Of course, the author of the function has to implement a function expecting to be used in this fashion. When the author creates such a function, we call it a constructor function.
In the above code we are using the new operator and the Point function to construct points with x and y properties, and an add method. In memory you can think of the end result like figure 6.
The problem now is we still have an add method inside of each point. Applying what we know about prototypes and inheritance, we’d prefer to have the add method in Point.prototype instead of each point. To achieve inheritance of the add method, all we need to do is modify the Point.prototype object.
Also – drive safely. You never know what new technology those other cars on the road might inherit from their prototypes.
About the Author
Scott Allen is the Principal Consultant and a founder of OdeToCode LLC, and also a member of the Pluralsight technical staff. Scott has more than 16 years of commercial software development experience with a wide range of technologies. He's delivered products on embedded, Windows, and web platforms. Scott writes the Extreme ASP.NET column for MSDN Magazine and is a featured speaker at conferences and workshops around the world.
Find Scott on: