JavaScript Prototypes

Having just started Hack Reactor, and as a first step into the world of blogging, if this may be called that, I thought I’d write a little bit about my understanding of prototypes in JavaScript, which as a concept is often fundamental, and as a term is often ambiguous.

What are prototypes?

In JavaScript, almost everything is an object, and every object has an internal property (sometimes denoted __proto__, [[prototype]] or simply called its prototype) which it relies on when resolving failed property lookups.

Note: for the rest of this article I will use [[prototype]] to denote this internal property.

If someone asks it for a property it doesn’t have, the prototype is checked. That means that whatever is stored inside [[prototype]] is what is checked next for the property, and if it doesn’t have the property then it’s own [[prototype]] is checked too, and so on until the property is found or the chain ends.

For example, take something like this piece of code:

var Item = function() {};
var myItem = new Item();

It results in something like this:

Created using draw.io

How can we use this?

We can really apply this to almost everything. It is this prototype mechanism that allows objects to reuse code from other objects, to inherit functionality from them. From this comes the ability to design a large variety of patterns for code reuse.

Beyond this basic mechanism there are a lot of great tools built in to the language that can then be combined into many different patterns. Tools like Object.create(), for setting the [[prototype]] of an object, the new keyword, for assisting in the creation of objects, and the ES6 class syntax which is intended to be a more familiar way to work with objects, especially for programmers coming from languages where general OOP concepts flow from a class-based implementation.

But what is confusing about prototypes then?

One more “convenience” that is built into the language, and which is often missed, is that whenever an object is created in JavaScript, if it is a function object it is automatically created with a property called .prototype. And precisely here is where the ambiguity begins. For all intents and purposes it's just an empty object, a container, a property like everything else and could just as easily be called .methods or some other such name (which may have even been nice for eliminating some of the ambiguity).

It is added automatically to every function object because the language has no way of knowing whether you plan to use the function as a constructor or not [1], but in case you do, it is there. Any subsequent object created by that function with the new keyword will have its own internal [[prototype]] set to the .prototype of that function, and any methods stored in the function's .prototype property are then available to those objects.

Here’s a quick and “imaginative” demonstration, straight from my Chrome developer tools console to clarify:

var Item = function() {}; // create the 'Item' function
Item.hasOwnProperty("prototype"); // true, automatically created
Item.__proto__ === Item.prototype; // false, not the same thing
Item.__proto__ === Function.prototype; // true
var myItem = new Item(); // myItem is just an object
myItem.hasOwnProperty("prototype"); // false, not automatic
myItem.__proto__ === Item; // false
myItem.__proto__ === Item.prototype; // true

For a more familiar example of this , let’s look at an array (which is also an object). Whether you use new Array() or just the literal syntax of [], that array will be made for you with the built-in array constructor (called Array and capitalized by convention as a constructor). Since Array is a function object, it comes with a .prototype property, on which are stored all its useful methods, like .slice() and .join(). If you call those methods from an array you make, the array itself won't have those methods, but it will find them inside Array.prototype because that is precisely what is stored in your array's internal [[prototype]] property. Open up your console (Ctrl+Shift+I in Chrome) and give it a try:

var arr = [1,2,3];
arr.hasOwnProperty("slice"); // false
arr.__proto__.hasOwnProperty("slice"); // true
arr.__proto__ === Array.prototype; // true
arr.__proto__; // expand to see a list of everything
Array.prototype; // expand to see same list

To summarize:

  • every object has an internal slot (which you generally don’t manipulate directly, though some environments will let you) that is used for failed property lookups
  • this internal slot is variously denoted [[prototype]], __proto__ or simply "its prototype"
  • all function objects have an extra property called .prototype
  • this .prototype is the one that is usually assigned as the value of the internal [[prototype]] for new objects being created by the function, whether via new or Object.create()
  • this .prototype property is essentially just an object that is there to hold stuff for objects constructed by the function to use