Understanding Prototype Inheritance in JavaScript

Introduction
JavaScript is often called a "weird" language, and a big part of that reputation comes from its quirky inheritance model. Unlike traditional class-based languages like Java or C++, JavaScript embraces prototype inheritance, a system where objects inherit properties and methods directly from other objects. Sounds fancy, right? Well, it is—and also quite powerful!
In this article, we’ll demystify prototype inheritance, break it down into digestible chunks, and throw in some fun examples along the way. By the end, you’ll be able to wield prototypes like a JavaScript wizard! 🧙♂️
The Definition
Every JavaScript object has an internal link to another object called its prototype. This prototype object serves as a blueprint from which other objects can inherit properties and methods.
Think of it like this: Imagine if you never had to clean your house because your neighbour’s house automatically cleaned itself and you inherited that magic. Prototypes are a bit like that—except they don’t do chores. 😅
You can check an object's prototype using:
console.log(Object.getPrototypeOf({}));
Or using the __proto__ property (though it's considered old-school and should be avoided in modern code):
console.log({}.__proto__);
How Prototype Inheritance Works
When you try to access a property on an object, JavaScript first looks for that property on the object itself. If it doesn’t find it, it starts climbing the prototype chain until it either finds the property or reaches null (the end of the chain).
Example:
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log(`Hello, my name is ${this.name}`);
};
const alice = new Person('Alice');
alice.greet(); // Output: Hello, my name is Alice
What’s happening here?
alicedoesn’t have agreetmethod of its own.JavaScript looks up
alice.__proto__, which points toPerson.prototype.It finds
greetthere and executes it.
It’s like borrowing your friend’s Netflix account when you don’t have one. Except JavaScript won’t revoke your access. 😉
The Prototype Chain
The prototype chain is the mechanism by which JavaScript objects inherit features from one another. Every object in JavaScript has a prototype, except for the base object at the top of the chain, which has null as its prototype.
Example:
console.log(Object.prototype.__proto__); // null
Let’s see the prototype chain in action with an array:
const numbers = [1, 2, 3];
console.log(numbers.__proto__ === Array.prototype); // true
console.log(numbers.__proto__.__proto__ === Object.prototype); // true
console.log(numbers.__proto__.__proto__.__proto__); // null
Arrays inherit from Array.prototype, which in turn inherits from Object.prototype. This is why arrays have access to both array methods (map, filter, forEach) and object methods (toString, hasOwnProperty).
Overriding Inherited Properties
Sometimes, you might want to customize an inherited method. If an object has a property or method with the same name as one in its prototype, the object’s own property takes precedence.
function Animal(name) {
this.name = name;
}
Animal.prototype.makeSound = function() {
console.log('Some generic sound');
};
const dog = new Animal('Dog');
dog.makeSound(); // Output: Some generic sound
dog.makeSound = function() {
console.log('Bark! Bark!');
};
dog.makeSound(); // Output: Bark! Bark!
The method lookup stops at dog since it now has its own makeSound method. Kind of like how a rebellious teenager might ignore their parents' rules and set their own. 😂
Using Object.create() for Prototype Inheritance
You can create objects with a specified prototype using Object.create(), which is often cleaner than constructor functions.
const animal = {
makeSound: function() {
console.log('Some generic sound');
}
};
const cat = Object.create(animal);
cat.makeSound(); // Output: Some generic sound
console.log(cat.__proto__ === animal); // true
This is useful when you want to create objects without defining a constructor function. Less boilerplate, more productivity! 🚀
Extras
The class Syntax and Prototype Inheritance
ES6 introduced the class syntax, which is syntactic sugar over prototype-based inheritance.
class Person {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello, my name is ${this.name}`);
}
}
class Student extends Person {
constructor(name, course) {
super(name);
this.course = course;
}
introduce() {
console.log(`I am ${this.name}, and I study ${this.course}`);
}
}
const bob = new Student('Bob', 'Computer Science');
bob.greet(); // Output: Hello, my name is Bob
bob.introduce(); // Output: I am Bob, and I study Computer Science
Under the hood, JavaScript still uses prototypes, but class makes things look a bit more civilized. 🤵
Summary
Prototype inheritance allows objects to inherit properties and methods from other objects.
JavaScript objects have a
__proto__property pointing to their prototype.If a property/method isn’t found on an object, JavaScript looks up the prototype chain.
Object.create()provides a clean way to create prototype-based inheritance.The
classsyntax is a modern, cleaner approach but still relies on prototypes.
Mastering prototype inheritance will make you a more efficient JavaScript developer. So go forth and prototype like a boss! 💪🚀




