Achieving Inheritance in JavaScript Without extends: Understanding "__proto__" in JS
In this blog, you'll develop a clear understanding of how the extends keyword functions and how inheritance works under the hood.

Engineer @Ciena | Software Engineering | Full Stack Development | Typescript , Java, React Node | DSA LeetCode (600+) | System Design |
In JavaScript, inheritance is usually done using the extends keyword in classes. But did you know that you can achieve inheritance without extends? This is possible using the __proto__ property, which links one object to another.
In this blog, we will break down how __proto__ works with super simple examples so that even beginners can understand it!
What is __proto__?
Every JavaScript object has a hidden property called __proto__, which points to the prototype of another object. This is how JavaScript enables prototype-based inheritance.
When you try to access a property/method that’s not in the object, JavaScript follows the prototype chain (__proto__) to find it in its parent. Lets discuss this in details:
Lets understand what happens when you try to access a property which is not defined in the class.

🛠️ Steps Explained in the Flowchart:
- Check Inside the Object Itself
- Check Inside the Class Prototype (
__proto__)
- Check Inside
Object.prototype
- Reached
null(End of Prototype Chain)
Inheritance Without extends Using __proto__
Let's say we have two classes: Person and Student. Normally, we would write class Student extends Person, but here, we’ll use __proto__ instead.
Step 1: Create Classes
// Here I am creating 2 classes
class Person {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello, my name is ${this.name}`);
}
}
class Student {
constructor(name, grade) {
this.name = name;
this.grade = grade;
}
study() {
console.log(`${this.name} is studying in grade ${this.grade}.`);
}
}
So far, Person has a method greet(), and Student has a method study(). But Student doesn’t inherit from Person yet.
Step 2: Link Student to Person Using __proto__
We want every student to also have access to greet() from Person.
We can achieve this by setting the prototype of Student.prototype to Person.prototype:
// Overriding the __proto__ property of Student by Person.prototype.
Student.prototype.__proto__ = Person.prototype;
Now, when a Student object tries to access a method that isn’t in Student, JavaScript will look inside Person.
Step 3: Create Objects and Test
const student1 = new Student("Amit", 10);
student1.study(); // ✅ Output: Amit is studying in grade 10.
student1.greet(); // ✅ Output: Hello, my name is Amit
What Happened Here?
student1.study()works becausestudy()is inStudent.student1.greet()works even thoughgreet()is not inStudent, because JavaScript looks insidePersonvia__proto__.
Now, we have successfully achieved inheritance without using extends! 🚀
Example 2: Multi-Level Inheritance Without extends
Let’s go a step further. Suppose we create another class, HighSchoolStudent, which should inherit from Student.
Step 1: Create the Class HighSchoolStudent and Link HighSchoolStudent to Student
class HighSchoolStudent {
constructor(name, grade, stream) {
this.name = name;
this.grade = grade;
this.stream = stream;
}
prepareForExams() {
console.log(`${this.name} is preparing for final exams in ${this.stream}.`);
}
}
// overriding HighSchoolStudent prototype to Student's
HighSchoolStudent.prototype.__proto__ = Student.prototype;
HighSchoolStudent will inherit from Student, and indirectly from Person.
Step 3: Create Objects and Test
const highSchoolStudent1 = new HighSchoolStudent("Neha", 12, "Science");
highSchoolStudent1.prepareForExams(); // ✅ Output: Neha is preparing for final exams in Science.
highSchoolStudent1.study(); // ✅ Output: Neha is studying in grade 12.
highSchoolStudent1.greet(); // ✅ Output: Hello, my name is Neha.
🎯 How Prototype Chain Works Here
When we call highSchoolStudent1.greet(), JavaScript searches:
HighSchoolStudent → Student → Person → Object.prototype → null
Since greet() is found inside Person, JavaScript calls it successfully!
Checking the Prototype Chain
If you want to check the prototype links, use this:
console.log(HighSchoolStudent.prototype.__proto__ === Student.prototype); // ✅ true
console.log(Student.prototype.__proto__ === Person.prototype); // ✅ true
console.log(Person.prototype.__proto__ === Object.prototype); // ✅ true
console.log(Object.prototype.__proto__ === null); // ✅ true
This confirms that JavaScript follows the prototype chain step by step.
Conclusion
✅ We achieved inheritance without using extends, just like JavaScript does behind the scenes.
✅ __proto__ allows us to manually link one class to another.
✅ JavaScript follows the prototype chain to find missing methods.
Now that you understand how extends works internally, try using __proto__ in your own projects!




