From Objects to Prototype Chains: Building an Intuition for JavaScript Prototypes

From Objects to Prototype Chains: Building an Intuition for JavaScript Prototypes

A Curious Observation About JavaScript Objects

Lets see the following code

const user = {
	name: 'vaibhav jain'
};
console.log(user.name); // "vaibhav jain"
console.log(user.toString()); // "[object Object]"

Lets have a look at output

Observe toString function does NOT exists on user, should not it be undefined instead ? Looks like user do have access to sometoString method, but where does this come from ?

Lets first understand few important topics

What Does a JavaScript Object Really Contain ?

Lets start from what is an object

An object is a collection of properties and has a single prototype object. — ECMAScript

user
├── firstName: 'vaibhav'
├── lastName: 'jain'
├── ... other properties
|
├── [[Prototype]]: ___________
└── ... other internal slots and internal methods

All ordinary object have an internal slot called [[Prototype]] . The value of this internal slot is either null or an object and is used for implementing inheritance

[[Prototype]] is one of the internal slot, the ECMAScript language provides. There is no direct way for programmers to manipulate or access these slots, hence the name internal or hidden, though it can be indirectly accessed using user.__proto__

Internal methods and internal slots are identified within this specification using names enclosed in double square brackets [[ ]].

— ECMAScript

Functions Come With a Special prototype Property.

Lets look at this function declaration

function Animal() {}

When the engine evaluates the function declaration, it creates a Function Object and adds a prototype property to it

NOTE : prototype property of Functions are different from [[Prototype]] internal slot. Don’t get confused between them.

For the above function, Animal Function object will be created with following properties :

Animal
├── prototype: ____ // JS engine adds this property to every Function Object
└── [[Prototype]]: ____ // since its an Object as well, so it also has [[Prototype]] internal slot

How Objects Get Linked Together ?

Now that we have understood objects have a hidden [[Prototype]] link, and functions have prototype object, lets see how these together leads to the prototype chain.

Lets consider the following code :

function Animal(name) {
	this.name = name;
}

const dog = new Animal('Tommy');

Step 1 : new Animal("Tommy") creates a new empty object {} and as discussed above, it also contains [[Prototype]] internal slot as well

Step 2 : The JavaScript engine sets the [[Prototype]] internal slot of dog to Animal.prototype

dog
└── [[Prototype]]: Animal.prototype

This means that dog inherits everything defined on Animal.prototype

Note that Animal.prototype is itself an object, and hence also contains [[Prototype]] internal slot.

Complete structure of dog object will look like following:

dog
└── [[Prototype]]: Animal.prototype
                   └── [[Prototype]]: Object.prototype
                                      └── [[Prototype]]: null

Its called Prototype chaining, Note that [[Prototype]] of Object.prototype is null , since the chain must end somewhere.

Step 3 : The constructor function Animal is then executed with this pointing to the newly created object.

this.name = 'Tommy';

So now the object dog looks like following :

dog
├── name: 'Tommy'
└── [[Prototype]]: Animal.prototype
                   └── [[Prototype]]: Object.prototype
                                      └── [[Prototype]]: null

How JavaScript Finds Properties ?

Let’s understand what happens when we execute dog.toString()

When evaluating obj.prop, ECMAScript invokes the object’s [[Get]] internal method. If the property is not found on the object itself, the algorithm recursively checks the object’s [[Prototype]] chain until the property is located or the prototype becomes null

Step 1 → Look inside dog
         ❌ not found

Step 2 → Follow [[Prototype]]
         Animal.prototype
         ❌ not found

Step 3 → Follow [[Prototype]]
         Object.prototype
         ✅ found toString

So the method toString is actually coming from Object.prototype . If a property is not found in the chain, Javascript returns undefined .

Now the Original Code Makes Sense !!

const user = {
	name: 'vaibhav jain'
};

For object literals, Javascript initializes [[Prototype]] with Object.prototype , so it inherits all the properties from Object including toString function

The user object looks like following

user
├── name: 'vaibhav jain'
└── [[Prototype]]: Object.prototype
                   └── [[Prototype]]: null

Putting It All Together

  • JavaScript objects are not isolated containers of properties — they are connected through prototypes, forming a chain that the engine follows during property lookup.
  • And this simple [[Prototype]] link is the foundation of JavaScript’s inheritance model.

Author’s Note

I enjoy breaking down complex JavaScript concepts into simple mental models.

If you found this useful, feel free to connect or share your thoughts by connecting with me on linkedin