Understanding the Prototype Chain

Mom. Software Engineer.
6 min readJun 17, 2023

--

This article is the first in a comprehensive five part series on Prototypal Inheritance.

Part 1 — Understanding the Prototype Chain
Part 2 — Prototypal Inheritance with Object.create
Part 3 — Prototypal Inheritance with Constructor Functions
Part 4 — Coming soon!
Part 5 — Coming soon!

When I transitioned from Java and C++ to JavaScript, I found the concept of Prototypal Inheritance extremely confusing. I simply could not get my head around it. It was too different from what I was used to.

Thus, I created this series to help developers who, much like my past self, are new to JavaScript and are trying to gain an in-depth understanding of prototype mechanics.

To make sure that you completely grasp all the concepts presented in this series, I provide exercises (and solutions) at the end of each part. I highly, highly recommend going through each exercise.

Feel free to reach out with questions! I would love your feedback and any constructive criticism you may have.

Part 1 — Understanding the Prototype Chain

In JavaScript, every object has a special connection called [[prototype]] that links it to another object known as its prototype. This prototype object can have its own prototype, forming a chain. The chain keeps going until it reaches an object with null as its prototype.

To visualize this, imagine a family tree, where each person has a parent, who in turn has their own parent, and so on. Similarly, objects in JavaScript have a prototype, and that prototype can have its own prototype as well.

Here is an example of a prototype chain:

Most JavaScript objects have Object.prototype as their prototype. However, there are certain objects that do not inherit directly from Object.prototype. For example:

  1. Objects created via Object.create(someProto) have someProto as their prototype. I’ll do an in-depth dive of Object.create in Part 2 of this series.
  2. Certain built-in objects in JavaScript, like Array, Function, RegExp, and Date, possess their own distinct prototypes (Array.prototype, Function.prototype, RegExp.prototype, and Date.prototype, respectively). Although the prototypes of these built-in objects might ultimately link toObject.prototype, the objects themselves do not directly have Object.prototype as their immediate prototype.

When attempting to access a property of an object, the search for that property extends beyond just the object itself. It continues on to the object’s prototype, the prototype of the prototype, and so forth, until either a property with a matching name is discovered or the end of the prototype chain is reached. If the search fails to find the desired property, the outcome of the operation is undefined for a value property or TypeError for a function-valued property.

I’ll illustrate the concept above by walking through two examples:

Example 1

const pumba = { 
name: 'Pumba',
age: 15
}
console.log(pumba.toString()) // [object object]

When we declare an object literal, like the one named pumba in the snippet above, it automatically getsObject.prototype as its prototype. Essentially, our little snippet above created the following prototype chain:

Notice that we never defined toString on pumba, so where did it come from? When we tried to access toString, and it wasn’t found on pumba, the JavaScript runtime checked pumba’s prototype, which happens to be Object.prototype. That object does, indeed, have the toString method.

In fact, if we console.log(Object.prototype) in the chrome console, we see the toString method along with other methods you might be familiar with.

Example 2

const arr = ['Pokity', 'Wokity', 'Lokity'];
console.log(arr.at(1)); // Wokity

How did our array, arr, get the at method? As mentioned above, the [[prototype]] reference of an array points to Array.prototype. I.e, the code above produces the following prototype chain:

If we examine the Array.prototype object in chrome’s console, we see

Array.prototype has the at method.

Now that we understand the prototype chain, the natural next question is, how do we access the prototype of an object obj? There are two primary ways:

  1. Object.getPrototypeOf(obj)
  2. obj.__proto__
const newObj = {
key: 'value'
}
console.log(newObj.__proto__ === Object.prototype); // true
console.log(Object.getPrototypeOf(newObj) === Object.prototype); // true

We will stick to Object.getPrototypeOf since the use of __proto__ is no longer recommended. For more details as to why, see here.

By this point, you should have a good overview of how the prototype chain works. Let’s move on and discuss the three primary ways of creating a prototype chain:

  1. Object.create
  2. Constructor Functions
  3. Class-Syntax Constructors

Continue to Part 2, Prototypal Inheritance with Object.create.

Exercises

Exercise 1

const myBirthday = new Date('December 11 1986'); 
console.log(myBirthday.getFullYear()); // 1986

We never defined the function, getFullYear, on myBirthday.

In fact, the statement myBirthday.hasOwnProperty(‘getFullYear’) evaluates to false.

Why are we not getting a TypeError when running the above code?

Solution

Date objects have Date.prototype as their prototype. Thus, we have the following prototype chain:

null ← Object.prototype ← Date.prototype ← myBirthday

You can verify this by executing the following code

console.log(Object.getPrototypeOf(myBirthday) === Date.prototype);
console.log(Object.getPrototypeOf(Date.prototype) === Object.prototype);
console.log(Object.getPrototypeOf(Object.prototype) === null);

Date.prototype does have the getFullYear method. The statement Date.prototype.hasOwnProperty(‘getFullYear’) evaluates to true.

Thus, when the JavaScript runtime could not find the getFullYear method on the myBirthday object, it checked it’s prototype, Date.prototype. That object does indeed have the getFullYear method, and so it executed it.

Full Disclosure: I am a developer at heart. I prefer writing things like dog.isWalking as opposed to ‘the dog is walking’. Given that I’ve been doing this for years, my English grammar skills have slowly but surely been deteriorating. As I was working on this series, I noticed that, well, at times, what I wrote sounded like gibberish. And so, I leaned on ChatGPT. I also tried generating images for this article using DALL·E 2; unfortunately, they were all … weird.

--

--

Mom. Software Engineer.
0 Followers

I am a mom to two beautiful daughters, and a Software Engineer. This blog is my very personal experience trying to navigate both identities.