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 becomesnull
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