Why You Should Understand Prototypes
When you start learning JavaScript, you’ll often hear this phrase:
In JavaScript, everything is an object.
But what’s often left out is how JavaScript handles inheritance not through classes (traditionally), but through prototypes.
In this post, we’ll explore:
- What prototypes are
- How the prototype chain works
__proto__
vs prototype
- How JavaScript uses prototypes for inheritance
- How ES6 classes relate to prototypes
- When and why you should care
What Is a Prototype?
In JavaScript, every object has an internal link to another object called its prototype.
This prototype object can have its own prototype, forming a prototype chain. The chain ends when a prototype is null
.
Think of it like a fallback mechanism — if a property or method isn’t found on an object, JavaScript looks up the chain.
Example
const person = {
greet() {
return "Hello!";
}
};
const student = Object.create(person);
student.name = "Toni";
console.log(student.name); // "Toni"
console.log(student.greet()); // "Hello!" (inherited from `person`)
Explanation
- student doesn’t have greet()
- JavaScript looks up the prototype chain (to person) and finds it there
The Prototype Chain in JavaScript
Every object in JavaScript has a hidden property [[Prototype]] (accessible via proto) that points to its prototype.
const obj = {};
console.log(obj.__proto__); // Same as Object.prototype
console.log(obj.__proto__.__proto__); // null (end of chain)
Diagram
student → person → Object.prototype → null
When you access student.greet(), JS will:
- Look for greet in student
- Not found? Check student.proto (which is person)
- Still not found? Go up again (to Object.prototype)
- If nowhere to be found → undefined
__proto__
vs prototype
: What’s the Difference?
This is a common confusion for new developers.
__proto__
The internal prototype of an instance
prototype
A property on constructor functions used to create new instances
Example with Constructor
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function () {
return `${this.name} makes a noise.`;
};
const dog = new Animal("Rex");
console.log(dog.speak()); // "Rex makes a noise."
console.log(dog.__proto__ === Animal.prototype); // true
dog.__proto__
points to Animal.prototype, where speak() is defined.
ES6 Classes & Prototypes
class Vehicle {
drive() {
console.log("Vroom!");
}
}
const car = new Vehicle();
car.drive(); // "Vroom!"
console.log(Object.getPrototypeOf(car) === Vehicle.prototype); // true
Even with class, JavaScript uses prototypes behind the scenes.
Why Use Prototypes?
Using prototypes provides several advantages:
- Memory efficiency — methods are shared across instances
- Performance — avoids recreating functions for every object
- Structure — clear inheritance paths
Anti-pattern Example
function User() {
this.sayHi = function () {
console.log("Hi!");
};
}
const u1 = new User();
const u2 = new User();
console.log(u1.sayHi === u2.sayHi); // false
Each sayHi is a separate function. That’s inefficient.
Recommended Prototype Approach
function User() {}
User.prototype.sayHi = function () {
console.log("Hi!");
};
const u1 = new User();
const u2 = new User();
console.log(u1.sayHi === u2.sayHi); // true
Common Pitfalls When Using Prototypes
Avoid these mistakes when working with prototypes:
- Don’t manually set
__proto__
— use Object.create() or a proper constructor
- Don’t overuse inheritance — favor composition where possible
- Prototype chain lookups are slower than direct property access
Helpful Built-in Methods for Working with Prototypes
Object.create(proto)Creates a new object with a given prototype
Object.getPrototypeOf(obj)Returns the prototype of obj
Object.setPrototypeOf(obj, proto)Sets the prototype (avoid for performance reasons)
instanceofChecks if proto exists in the object’s prototype chain
hasOwnProperty()Checks if the property exists on the object itself, not its prototype
Debugging Prototype Issues
Use DevTools in your browser to inspect prototype chains.
Try these in the console:
Object.getPrototypeOf(obj);
obj.hasOwnProperty('prop');
console.dir(obj);
Conclusion
Understanding how JavaScript handles prototypes gives you the power to write clean, reusable, and performant code.
Key Takeaways
- Every object in JS has a prototype, forming a chain
- Inheritance flows up the prototype chain
- Constructor functions and class use prototypes
- Prototypes help reduce memory usage and improve structure
- Don’t manually tinker with
__proto__
— use proper patterns
If you’re still thinking only in classes, you’re missing JavaScript’s true inheritance model.