Object Prototypes & Inheritance in JavaScript
In JavaScript, prototypes and inheritance form the foundation of the language’s object-oriented behavior. Every JavaScript object is linked to another object, called its prototype, from which it can inherit properties and methods.
This system is known as prototypal inheritance, and it allows objects to share behavior efficiently without duplicating code.
What is a Prototype?
A prototype is an object from which other objects inherit properties and methods.
Every JavaScript object has an internal link ([[Prototype]]
) that points to another object — accessible through the special property __proto__
or via Object.getPrototypeOf()
.
Example:
const person = {
greet() {
console.log("Hello!");
}
};
const student = Object.create(person);
student.study = function() {
console.log("Studying...");
};
student.greet(); // Inherited from person -> "Hello!"
student.study(); // Own method -> "Studying..."
The Prototype Chain
When you access a property or method on an object:
- JavaScript first looks for it on the object itself.
- If not found, it looks up the prototype chain until it finds it or reaches
null
.
Example:
If the property isn’t found even at the top of the chain (Object.prototype
), it returns undefined
.
console.log(student.__proto__ === person); // true
console.log(Object.getPrototypeOf(student) === person); // true
Constructor Functions and Prototypes
Constructor functions use the prototype
property to define shared methods.
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(); // "Hello, my name is Alice"
Inheritance with Constructor Functions
You can create inheritance using constructor functions and prototypes:
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log(`Hello, I'm ${this.name}`);
};
function Student(name, subject) {
Person.call(this, name); // Inherit properties
this.subject = subject;
}
// Inherit methods
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
Student.prototype.study = function() {
console.log(`${this.name} studies ${this.subject}`);
};
const bob = new Student("Bob", "Math");
bob.greet(); // "Hello, I'm Bob"
bob.study(); // "Bob studies Math"
Inheritance Using ES6 Classes (Modern Approach)
ES6 introduced classes as syntactic sugar over prototypes.
extends
→ sets up the prototype chain automatically
super()
→ calls the parent constructor
Example:
class Person {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello, I'm ${this.name}`);
}
}
class Student extends Person {
constructor(name, subject) {
super(name); // Calls parent constructor
this.subject = subject;
}
study() {
console.log(`${this.name} studies ${this.subject}`);
}
}
const alice = new Student("Alice", "Physics");
alice.greet(); // "Hello, I'm Alice"
alice.study(); // "Alice studies Physics"
The Object Prototype Hierarchy
At the top of all JavaScript objects is Object.prototype
, which provides built-in methods like:
hasOwnProperty()
toString()
valueOf()
Example:
console.log(Object.getPrototypeOf({}) === Object.prototype); // true
console.log(Object.getPrototypeOf(Object.prototype)); // null
Advantages of Prototypal Inheritance
- Memory-efficient (methods shared across objects)
- Dynamic (new properties can be added at runtime)
- Flexible (supports object-to-object linking)