JavaScript Prototypes Explained: A Complete Beginner's Guide
Introduction
If you've been learning JavaScript, you've probably heard the term prototype many times. At first, it can seem confusing because JavaScript doesn't use traditional class-based inheritance like Java or C++. Instead, JavaScript uses prototype-based inheritance.
Understanding prototypes is one of the biggest milestones in becoming a strong JavaScript developer. Once you understand how prototypes work, concepts like inheritance, constructor functions, classes, new, and object methods become much easier.
In this blog, we'll learn prototypes from scratch with simple explanations, diagrams, and practical examples.
What is a Prototype?
A prototype is simply another object from which an object inherits properties and methods.
Every JavaScript object has a hidden internal property called [[Prototype]]. In most browsers, you can access it using:
__proto__
Whenever JavaScript cannot find a property or method inside an object, it automatically searches in its prototype.
This lookup process is called the Prototype Chain.
Think of it Like Real Life
Imagine a student asking questions.
Student
↓
Teacher
↓
Principal
If the student doesn't know the answer, they ask the teacher.
If the teacher doesn't know, they ask the principal.
JavaScript behaves in the same way.
If an object doesn't contain a property, JavaScript checks its prototype. If it's still not found, JavaScript continues checking higher prototypes until it reaches null.
Your First Prototype Example
const person = {
name: "Sai"
};
console.log(person.name);
Output
Sai
JavaScript finds name directly inside the object.
But now look at this:
console.log(person.toString());
We never created a toString() method.
Why does it work?
Because JavaScript searches inside Object.prototype, where toString() already exists.
The lookup happens like this:
person
↓
Object.prototype
↓
null
Every Object Has a Prototype
Let's inspect it.
const person = {
name: "Sai"
};
console.log(person.__proto__);
Output
Object.prototype
We can even verify it.
console.log(person.__proto__ === Object.prototype);
Output
true
This proves that every ordinary object inherits from Object.prototype.
Object.prototype
Object.prototype is the root object for almost every JavaScript object.
It already contains useful methods such as:
toString()hasOwnProperty()valueOf()isPrototypeOf()propertyIsEnumerable()
Example:
const obj = {};
console.log(obj.hasOwnProperty("name"));
Output
false
Even though we never created hasOwnProperty(), it is inherited from Object.prototype.
Understanding the Prototype Chain
Consider two objects.
const animal = {
eats: true
};
const dog = {
barks: true
};
dog.__proto__ = animal;
console.log(dog.eats);
Output
true
How did JavaScript find eats?
Search process:
dog
│
└── eats? ❌
animal
│
└── eats? ✅
Since JavaScript finds the property in the prototype, it returns true.
Visualizing the Prototype Chain
dog
{
barks: true
}
↓
animal
{
eats: true
}
↓
Object.prototype
↓
null
Whenever a property is requested, JavaScript searches from top to bottom until it finds it.
Using Object.create()
Instead of manually changing __proto__, modern JavaScript recommends using Object.create().
const animal = {
eats: true
};
const dog = Object.create(animal);
dog.barks = true;
console.log(dog.eats);
Output
true
Prototype relationship
dog
↓
animal
↓
Object.prototype
Why Prototypes Save Memory
Suppose we create two users.
Without prototypes:
const user1 = {
name: "Sai",
greet() {
console.log("Hello");
}
};
const user2 = {
name: "Ram",
greet() {
console.log("Hello");
}
};
Each object stores its own copy of greet().
This wastes memory.
Instead, create one shared object.
const userMethods = {
greet() {
console.log("Hello");
}
};
const user1 = Object.create(userMethods);
user1.name = "Sai";
const user2 = Object.create(userMethods);
user2.name = "Ram";
Now both objects share the same function.
user1
↓
userMethods
↑
user2
Only one copy of greet() exists in memory.
Constructor Functions and Prototypes
Before ES6 classes, JavaScript commonly used constructor functions.
function Person(name) {
this.name = name;
}
Methods are added to the prototype.
Person.prototype.greet = function () {
console.log("Hello " + this.name);
};
Creating objects:
const p1 = new Person("Sai");
const p2 = new Person("Ram");
p1.greet();
p2.greet();
Output
Hello Sai
Hello Ram
Notice that both objects use the same greet() method.
What Happens When You Use new?
When you write:
const person = new Person("Sai");
JavaScript performs four steps:
Step 1
Creates a new empty object.
{}
Step 2
Connects it to Person.prototype.
new object
↓
Person.prototype
Step 3
Calls the constructor.
Person.call(newObject, "Sai");
Inside the constructor:
this.name = "Sai";
becomes
newObject.name = "Sai";
Step 4
Returns the new object.
ES6 Classes Still Use Prototypes
Modern JavaScript introduced classes.
class Person {
constructor(name) {
this.name = name;
}
greet() {
console.log("Hello " + this.name);
}
}
Creating an object:
const person = new Person("Sai");
person.greet();
Output
Hello Sai
Although the syntax looks different, JavaScript internally stores greet() inside Person.prototype.
Classes are simply syntactic sugar over prototypes.
Property Shadowing
A child object can override properties from its prototype.
const animal = {
legs: 4
};
const dog = Object.create(animal);
console.log(dog.legs);
Output
4
Override it.
dog.legs = 3;
console.log(dog.legs);
Output
3
Now JavaScript finds legs directly inside dog, so it doesn't continue searching.
Checking Where a Property Exists
const animal = {
eats: true
};
const dog = Object.create(animal);
dog.name = "Tom";
console.log(dog.hasOwnProperty("name"));
Output
true
Now check another property.
console.log(dog.hasOwnProperty("eats"));
Output
false
The property exists through inheritance, not inside dog.
Complete Prototype Chain Example
const livingThing = {
alive: true
};
const animal = Object.create(livingThing);
animal.eats = true;
const dog = Object.create(animal);
dog.barks = true;
console.log(dog.alive);
console.log(dog.eats);
console.log(dog.barks);
Output
true
true
true
Search order:
dog
↓
animal
↓
livingThing
↓
Object.prototype
↓
null
Why Are Prototypes Important?
Prototypes provide several advantages:
- Enable inheritance between objects.
- Allow methods to be shared instead of duplicated.
- Reduce memory consumption.
- Improve application performance.
- Form the foundation of JavaScript's object-oriented programming model.
Without prototypes, every object would need its own copy of every method.
Interview Questions
What is a prototype?
A prototype is an object from which another object inherits properties and methods.
What is the prototype chain?
The sequence of objects JavaScript searches when a property isn't found on the current object.
Why use Object.create()?
It creates a new object with a specified prototype and is the recommended alternative to modifying __proto__.
What is Object.prototype?
It is the root prototype for most JavaScript objects and contains built-in methods like toString() and hasOwnProperty().
Are ES6 classes different from prototypes?
No. Classes are simply cleaner syntax built on top of JavaScript's prototype system.
What does the new keyword do?
- Creates a new object.
- Links it to the constructor's prototype.
- Executes the constructor with
thispointing to the new object. - Returns the newly created object.
Key Takeaways
- Every JavaScript object has a hidden prototype (
[[Prototype]]). - JavaScript follows the prototype chain when searching for properties.
- Most objects inherit from
Object.prototype. -
Object.create()is the preferred way to establish prototype inheritance. - Constructor functions share methods using
.prototype. - ES6 classes are built on top of the prototype system.
- Prototypes make JavaScript memory-efficient by allowing objects to share methods instead of creating duplicate copies.
Conclusion
Prototypes are one of JavaScript's most powerful features. While they may seem challenging initially, understanding them unlocks many advanced concepts such as constructor functions, inheritance, classes, and the new keyword.
The next time you call methods like toString() or hasOwnProperty(), remember that those methods aren't stored directly in your object—they come from the prototype chain.
Top comments (0)