How Does Prototypal Inheritance Work in JavaScript? A Complete Technical Guide
Prototypal inheritance in JavaScript works through a hidden [[Prototype]] link that forms a chain; when you access a property, the engine traverses this chain until it finds the property or reaches null.
Unlike classical class-based languages, JavaScript implements inheritance via objects that serve as prototypes for other objects. This mechanism is documented in the h5bp/Front-end-Developer-Interview-Questions repository within src/questions/javascript-questions.md, where it appears as a core interview topic testing deep language understanding.
The Prototype Chain Mechanism
Every JavaScript object has an internal slot called [[Prototype]] (exposed via Object.getPrototypeOf() or the legacy __proto__ accessor) that references another object or null. When you attempt to read a property, JavaScript first checks the object itself. If the property is missing, the engine walks up the [[Prototype]] chain until it locates the property or exhausts the chain.
This design enables delegation-based inheritance—objects delegate property lookups to their prototypes rather than copying behavior.
Constructor Functions and the prototype Property
Constructor functions provide the traditional pattern for creating prototypal inheritance. When you invoke a function with the new keyword, JavaScript creates an object whose [[Prototype]] references the constructor’s prototype property.
function Person(name) {
this.name = name;
}
Person.prototype.greet = function () {
return `Hello, I'm ${this.name}`;
};
const alice = new Person('Alice');
console.log(alice.greet()); // "Hello, I'm Alice"
In this pattern, alice does not contain greet directly; the method lives once on Person.prototype, and all instances share it through the prototype chain.
Creating Inheritance with Object.create()
For direct object-to-object inheritance without constructors, Object.create(proto) explicitly sets the [[Prototype]] of a new object to proto.
const vehicle = {
wheels: 4,
drive() { return 'vroom'; }
};
const car = Object.create(vehicle);
car.color = 'red';
console.log(car.drive()); // 'vroom' (inherited from vehicle)
console.log(car.wheels); // 4 (inherited from vehicle)
To establish deeper hierarchies with constructors, manually link prototypes using Object.create() within the src/_data/helpers.js pattern of utility composition:
function Shape(name) {
this.name = name;
}
Shape.prototype.area = function () {
return 0;
};
function Circle(radius) {
Shape.call(this, 'circle'); // Inherit instance properties
this.radius = radius;
}
// Set up the prototype chain
Circle.prototype = Object.create(Shape.prototype);
Circle.prototype.constructor = Circle; // Restore constructor reference
Circle.prototype.area = function () {
return Math.PI * this.radius ** 2;
};
const c = new Circle(5);
console.log(c.area()); // 78.5398...
ES6 Classes: Syntactic Sugar Over Prototypes
The class and extends keywords introduced in ES2015 do not alter the underlying prototypal mechanism; they provide cleaner syntax for the same delegation patterns found in config/eleventy.config.js and other modern JavaScript files.
class Animal {
constructor(species) {
this.species = species;
}
speak() {
return `${this.species} makes a sound`;
}
}
class Dog extends Animal {
constructor(name) {
super('dog');
this.name = name;
}
speak() {
return `${this.name} barks`;
}
}
Under the hood, extends still manipulates [[Prototype]] links between Dog.prototype and Animal.prototype, and super() invokes Animal.call(this, ...).
Memory Efficiency and Dynamic Behavior
Prototypal inheritance offers two architectural advantages critical for high-performance applications referenced in the README.md:
- Memory efficiency: Shared methods exist once on the prototype, not duplicated across every instance.
- Dynamic updates: Adding methods to a prototype at runtime immediately makes them available to all existing instances.
Summary
- Prototypal inheritance delegates property lookups through a chain of objects linked via
[[Prototype]]. - Constructor functions use the
prototypeproperty to share methods across instances created withnew. - Object.create(proto) creates objects with an explicit prototype without using constructors.
- ES6 classes are syntactic sugar that compiles down to the same prototype-based delegation.
- The implementation files
src/questions/javascript-questions.mdandsrc/_data/helpers.jsdemonstrate how these patterns appear in real-world codebases.
Frequently Asked Questions
What is the difference between __proto__ and prototype?
prototype is a property of constructor functions that becomes the [[Prototype]] of instances created with new, while __proto__ (or Object.getPrototypeOf) is the accessor for an object's actual internal [[Prototype]] link. Every object has [[Prototype]], but only functions have prototype.
Why is Object.setPrototypeOf discouraged in production code?
Mutating an object's prototype after creation with Object.setPrototypeOf or obj.__proto__ = proto de-optimizes the engine's hidden class representations, causing significant performance degradation in V8 and other JavaScript engines. Set prototypes at object creation time using Object.create instead.
How does property lookup actually traverse the chain?
When accessing obj.property, JavaScript checks:
- The object itself.
- Its
[[Prototype]]. - The prototype's
[[Prototype]], continuing until reachingnull. If the property is found as a method,thisremains bound to the original object, enabling method inheritance while maintaining instance context.
Does JavaScript have multiple inheritance?
JavaScript objects can only inherit directly from one prototype chain ([[Prototype]] is a single reference). However, you can mix behaviors using composition patterns—assigning methods from multiple source objects to a single target—rather than true multiple inheritance.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →