Prototypes & Prototype Inheritance in JavaScript
prototype-chain-diagram.png: "Illustration of the prototype chain in JavaScript object inheritance
JavaScript is a powerful, object-oriented language that uses a unique inheritance model known as prototypal inheritance. At the heart of this model is the concept of prototypes, which allow objects to share properties and methods, enhancing memory efficiency and modularity.
In this article, we'll explore what prototypes are, how prototype inheritance works, and how it differs from classical inheritance found in languages like Java or C++.
A prototype is an object that other objects inherit from. Every JavaScript object has an internal property called [[Prototype]]
(accessible via __proto__
in modern browsers), which links to another object — the prototype.
This mechanism forms a prototype chain, allowing objects to inherit features from other objects.
const animal = {
speak() {
console.log("Animal speaks");
}
};
const dog = Object.create(animal);
dog.bark = function () {
console.log("Dog barks");
};
dog.speak(); // Animal speaks
dog.bark(); // Dog barks
Here, dog
inherits from animal
, and gains access to its speak()
method.
Constructor functions are a traditional way of creating objects and setting up prototype inheritance in JavaScript.
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function () {
console.log(`${this.name} makes a sound`);
};
const cat = new Animal("Whiskers");
cat.speak(); // Whiskers makes a sound
Animal.prototype.speak
is shared across all instances.
The cat
object does not have its own speak()
method but inherits it from Animal.prototype
.
Object.create()
You can also use Object.create()
for inheritance without constructor functions:
const vehicle = {
type: "Generic Vehicle",
start() {
console.log(`${this.type} is starting...`);
}
};
const car = Object.create(vehicle);
car.type = "Car";
car.start(); // Car is starting...
This method is clean and functional, and avoids some of the complexities of constructor functions.
Let’s create inheritance between two constructor functions using the prototype chain:
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function () {
console.log(`${this.name} makes a sound`);
};
function Dog(name, breed) {
Animal.call(this, name); // Inherit properties
this.breed = breed;
}
Dog.prototype = Object.create(Animal.prototype); // Inherit methods
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function () {
console.log(`${this.name} barks`);
};
const rex = new Dog("Rex", "Labrador");
rex.speak(); // Rex makes a sound
rex.bark(); // Rex barks
ES6 class
syntax provides a cleaner, more readable way to define prototype-based inheritance.
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a sound`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name);
this.breed = breed;
}
bark() {
console.log(`${this.name} barks`);
}
}
const leo = new Dog("Leo", "Beagle");
leo.speak(); // Leo makes a sound
leo.bark(); // Leo barks
Even though this looks like classical OOP, it’s still prototypal under the hood.
Memory-efficient: Methods are shared among instances.
Flexible: Objects can inherit from other objects easily.
Dynamic: You can add properties to prototypes at runtime.
Faster lookups: Inheritance is done via chain traversal.
Understanding prototypes and prototype inheritance is key to mastering JavaScript’s object-oriented capabilities. Whether you use constructor functions, Object.create()
, or ES6 classes, prototypes are the foundation of how inheritance works in JavaScript.
Grasping this concept will help you write efficient, modular, and maintainable code — whether you're working on small scripts or large-scale applications.