JS Prototype chain mechanism
This is my second post in the series of “JS: Leave the classes to those other languages”. If you haven’t checked out the first post, you can read it on JS: Leave the classes to those other languages.
Objects
In JavaScript almost everything is an object. But what are objects in JS?
- Objects are collections of key/value pairs
- Objects can be declared essentially in two ways: a literal or a constructed form
- Every object is linked internally to another object (its prototype)
The literal form
The literal syntax for an object looks like this:
And here is a mental map of what actually happens:
JS is, of course, creating an object car
with a color property ‘red’ but it is also automatically creating an internal link between car
and Object.prototype
. Object.prototype
contains all the built-in methods (i.e. toString()
) which every object normally can use and it becomes in our case the car
object prototype. JS do automatically this for us when we use the literal form.
The constructed form
The constructed form to obtain the same sort of object looks like this:
And here is a mental map of what actually happens:
Here things start to be no more immediate. The first time I saw this code I was almost sure to create an instance of the Object
class and assign it to the variable car
. I was far away from what happens.
JS does not have classes. Object
is just a function and I’m using this function as a constructor here.
It sounds contorted and it actually is. Personally I don’t like to use the new
keyword because it was written into the language to act more like Java and I find its use very confusing. We are not working with classes here.
Let’s break down this code to have a better understanding of what’s going on behind the scenes.
What is a function?
A function is a sub-type of object (technically, a “callable object”). Functions in JS are said to be “first class” in that they are basically just normal objects, and so they can be handled like any other plain object.
Like any object a function can have properties. Functions automatically get a property called prototype
, which is just an empty object.
What is a constructor?
A constructor is any function which is used as a constructor.
JS doesn’t make a distinction. A function can be written to be used as a constructor or to be called as a normal function, or to be used either way. I’m using here the Vehicle
function as a constructor putting the new
operator before the function call.
What happens when the constructor is called?
- It creates a new object
myVehicle
- It sets the constructor property of the object to
Vehicle
- It sets up the object to delegate to
Vehicle.prototype
- It calls
Vehicle()
in the context of the new object
The ES5 Object.create() method
EcmaScript 5 introduces a much simpler and more straightforward way to create an object.
The Object.create()
method creates a new object with the specified prototype.
We can specify a particular prototype for a new object without using any function as a constructor.
If you need to support pre-ES5 environments (like older IE’s), here is a simple partial polyfill for Object.create()
that gives us the capability that we need even in those older JS environments.
This polyfill works by using a throw-away F
function and overriding its .prototype
property to point to the object we want to link to. Then we use new F()
construction to make a new object that will be linked as we specified.
Object.create()
method will be the main character in OLOO style pattern.
The prototype chain
Once understood how to declare objects we need to learn how JS retrieves properties from objects. It uses the prototype chain mechanism I explain here through a practical example. Here is the code:
Here is a mental map of the prototype chain generated by the code above.
When we try to retrieve the border
property of triangle
, JS firstly looks up in the triangle
object. If it can’t find such a property, it tries to retrieve the property looking in the triangle
’s prototype. In our case triangle
’s prototype is the shape
object and JS just returns the value contained in the shape
border
property (‘red’ in our case).
Similar things happen when we try to retrieve a property the prototype chain does not contain. JS looks through all the chain until it finds the primitive null
; at this point it returns undefined
because it has not been able to find any property with such a key name in the whole prototype chain.
Now that we got a general understanding of how we can declare an object and how the prototype chain works we can carry on and explore pseudoclasses in JS.