Understanding __proto__ vs prototype in JavaScript
April 27, 2025
~4 min read
JavaScriptOOPPrototypes
Introduction
JavaScript's prototype system is one of its most powerful features, but it can be confusing to understand the difference between __proto__ and prototype. In this post, we'll explore both concepts with clear examples and deep insights into how they work.
What is a Prototype?
A prototype in JavaScript is a mechanism that allows objects to inherit properties and methods from other objects. Think of it as a template or a blueprint that other objects can use to share common functionality.
In JavaScript, every object has a prototype, which is another object that it inherits from. This creates a chain of inheritance, known as the prototype chain.
The Basics
Let's start with the fundamental concepts:
- prototype is a property of constructor functions. It defines the properties and methods that will be shared by all instances of the constructor.
- __proto__ is a property of objects that points to their prototype. It is the actual link between objects in the prototype chain.
According to the ECMAScript specification, every object in JavaScript has an internal `[[Prototype]]` property, which is exposed to user-level code via the `__proto__` property. This is what makes JavaScript's prototype-based inheritance possible.
Simple Example
Let's look at a simple example to understand the relationship:
javascript
1// Constructor function
2 function Person(name) {
3 this.name = name;
4 }
5
6 // Adding a method to the prototype
7 Person.prototype.sayHello = function() {
8 console.log(`Hello, I'm ${this.name}`);
9 };
10
11 // Creating an instance
12 const person = new Person('John');
13
14 // The relationship between __proto__ and prototype
15 console.log(person.__proto__ === Person.prototype); // true
16 console.log(person.sayHello()); // "Hello, I'm John"
Understanding the Chain
When you try to access a property on an object, JavaScript follows this process:
- Check if the property exists on the object itself
- If not, check the object's __proto__ (which points to the constructor's prototype)
- Continue up the prototype chain until the property is found or the chain ends
This mechanism is known as dynamic dispatch or delegation. Unlike static dispatch (where references are resolved at compile time), dynamic dispatch resolves references at runtime, allowing for full mutability of the inheritance chain.
Complex Example
Let's explore a more complex example with inheritance:
javascript
1// Base class
2 function Animal(name) {
3 this.name = name;
4 }
5
6 Animal.prototype.makeSound = function() {
7 console.log('Some generic sound');
8 };
9
10 // Derived class
11 function Dog(name, breed) {
12 // Call the Animal constructor to initialize 'name' in the Dog instance
13 Animal.call(this, name); // <-- This ensures Dog instances get the 'name' property from Animal
14 this.breed = breed;
15 }
16
17 // Set up inheritance
18 Dog.prototype = Object.create(Animal.prototype);
19 Dog.prototype.constructor = Dog;
20
21 // Add Dog-specific method
22 Dog.prototype.bark = function() {
23 console.log('Woof!');
24 };
25
26 // Create instances
27 const dog = new Dog('Rex', 'German Shepherd');
28
29 // The prototype chain
30 console.log(dog.__proto__ === Dog.prototype); // true
31 console.log(dog.__proto__.__proto__ === Animal.prototype); // true
32 console.log(dog.__proto__.__proto__.__proto__ === Object.prototype); // true
33
34 // Method calls
35 dog.makeSound(); // "Some generic sound"
36 dog.bark(); // "Woof!"
Note on
Object.create
: Object.create(proto)
creates a new object and sets its prototype to proto
. This is the recommended way to set up inheritance in JavaScript, as it cleanly establishes the prototype chain without invoking the constructor of the parent. In the example above, Dog.prototype = Object.create(Animal.prototype)
means all Dog instances inherit from Animal, but the Animal constructor is not called when setting up the prototype.Key Differences
Aspect | prototype | __proto__ |
---|---|---|
What is it? | A property of constructor functions | A property of all objects (instances) |
Purpose | Defines properties/methods shared by all instances | Points to the object's prototype (the actual link in the chain) |
Where is it found? | On constructor functions (e.g., Person.prototype) | On all objects (e.g., person.__proto__) |
How is it used? | To add shared methods/properties for instances | To traverse the prototype chain for inheritance |
Best Practice | Use to define shared behavior | Avoid direct manipulation; use Object.getPrototypeOf/setPrototypeOf |
Best Practices
- Use
Object.create()
for setting up inheritance - Avoid modifying
__proto__
directly - Use
Object.getPrototypeOf()
instead of__proto__
when possible - Remember to set the constructor property when creating custom prototype chains
- Use
Object.setPrototypeOf()
for changing prototypes after object creation
Class-based Inheritance
It's important to note that class-based inheritance in JavaScript is implemented on top of the prototype-based delegation. When you use the
class
keyword, it's essentially syntactic sugar that:- Creates a constructor function
- Sets up the prototype chain
- Handles method inheritance
- Manages the
super
keyword
Conclusion
Understanding the difference between __proto__ and prototype is crucial for working with JavaScript's object-oriented features. While __proto__ represents the actual prototype chain link, prototype is used to define shared properties and methods for all instances of a constructor function. This prototype-based inheritance system is what makes JavaScript so flexible and powerful.