Prototypal vs Classical Inheritance in JavaScript
Understanding inheritance in JavaScript requires distinguishing
between classical inheritance and prototypal inheritance. While
classical inheritance relies on classes acting as blueprints to
instantiate new objects, JavaScript natively uses prototypal
inheritance, where objects inherit directly from other objects through a
prototype chain. Although JavaScript introduced the class
keyword in ES6, it remains a syntactic layer over its native prototypal
system rather than a true implementation of classical OOP.
Fundamental Concepts
Classical Inheritance
In traditional object-oriented languages like Java, C++, or C#, inheritance is class-based: * Classes as Blueprints: A class defines the structure, properties, and methods. Instances are concrete allocations of memory created from these blueprints. * Rigid Hierarchies: Relationships are defined at compile time, leading to deep, immutable class hierarchies. * Instantiation Copying: When an instance is created, methods and attributes are typically copied or bound to the instance according to the class specification.
Prototypal Inheritance
JavaScript relies on a direct object-to-object linkage model: *
Objects Inherit from Objects: There are no abstract
blueprints required. Any existing object can serve as a prototype for
another object. * Delegation via Prototype Chain: When
a property or method is accessed on an object, JavaScript checks the
object itself. If not found, it traverses up the
[[Prototype]] chain until it finds the property or reaches
null. * Dynamic and Mutable: Prototypes
can be augmented or modified at runtime, and all descendant objects
immediately reflect these changes.
Key Differences
| Feature | Classical Inheritance | Prototypal Inheritance (JavaScript) |
|---|---|---|
| Inheritance Target | Classes inherit from other classes | Objects inherit from other objects |
| Instantiation | Uses constructors/classes to build instances | Uses object delegation
(Object.create, prototype) |
| Structure | Static and compile-time defined | Dynamic and runtime modifiable |
| Coupling | High coupling via strict hierarchies | Loose coupling via composition and delegation |
How Prototypal Inheritance Works in Practice
JavaScript implements prototypal inheritance through the prototype chain. When using standard object creation methods, delegation occurs automatically:
const vehicle = {
drive() {
return "Moving forward";
}
};
// Inherit directly from vehicle
const car = Object.create(vehicle);
car.doors = 4;
console.log(car.doors); // 4 (own property)
console.log(car.drive()); // "Moving forward" (delegated to vehicle)The ES6 class Syntax
The introduction of the class syntax in ES6 did not
alter JavaScript’s underlying execution model.
class Animal {
constructor(name) {
this.name = name;
}
speak() {
return `${this.name} makes a noise.`;
}
}Under the hood, Animal remains a function, and
speak is attached to Animal.prototype. The
class keyword simplifies syntax for developers familiar
with classical languages, but the engine continues to execute standard
prototypal delegation.