Understanding Prototypal Inheritance in Javascript
January 7th, 2025 | By Ezekiel Lawson | 11 min read
JavaScript’s inheritance system works differently from what many developers might expect. In other languages, inheritance often happens through classes, but in JavaScript, objects directly inherit from other objects. This can initially feel unusual, but it's powerful once you master it. In this article, we will explain in simple terms how it works in JavaScript.
What is Prototypal Inheritance?
Prototypal inheritance is a mechanism in JavaScript where objects inherit properties and methods directly from other objects through a prototype chain. This allows new objects to use features from existing ones without duplicating the code.
As a JavaScript developer, have you ever considered how objects like strings and arrays "inherit" methods like `.toLowerCase()` and `.sort()` when we don't manually define them? Well, this may look tricky to some people, but here is how it works: These methods come in a ready-to-use template in each type of data structure with the help of Prototypal Inheritance.
This is like buying a new phone and having pre-installed apps like the camera, clock, browser, calendar, note, and messaging app on your phone. You know that when you buy a phone, these features are already there for you to use.
JavaScript Objects
Did I just mention "Object" in this article? Yes, I did and that's exactly what we'll be discussing in this section as well. Before we proceed further into prototypal inheritance, let's first understand how a JavaScript object works through a short code example.
let studentProfile = {
name: "John Mark",
course: "Computer Science",
unit: 4,
printProfile: function() {
console.log("Hello, I'm " + this.name + ". I study " + this.course + " and my course unit is " +
this.unit);
}
};
studentProfile.printProfile();
JavaScript object is a collection of key-value pairs, where each key is associated with a value. These values can be simple data types like strings or numbers, functions referred to as methods when used within objects, or even other objects.
Dot notation can be used to access an object's properties, add new properties, or change existing ones.
const studentProfile = {
name: "John Mark",
course: "Computer Science",
unit: 4,
};
console.log(studentProfile.name)
console.log(studentProfile.course)
console.log(studentProfile.grade)
Output:
In the code example above, when we search for a property in the object, we retrieve the correct value assigned to it. However, if we try to access a property that doesn’t exist in the object, the result will be `undefined`. This happens because the property is not found in the object's property chain.
This leads us to an important question: What exactly is a property chain? Well, you need to relax as we proceed to learn what it is and how it works.
What is the Property Chain?
A property chain is a sequence of objects linked together through prototypes. In JavaScript, this chain allows objects to inherit properties and methods from other objects.
Before we encounter the `undefined` error in the previous example, JavaScript doesn't just check the object itself. It also looks through the object's prototype for a matching property, and it continues to the prototype chain until it either finds the property or reaches the end of the chain.
Every object in JavaScript has an internal property called `[[Prototype]]`, which references another object. While this property is commonly accessed using the `__proto__` property, this method is outdated to current users. However, I will explain both the old approach and the current, more modern way of accessing it to ensure everyone is on the same page.
Code Example:
Let's take, for instance, two students sharing the same course. They share details like the course name, instructor, and class schedule. However, they also have their own unique traits that make them different. Instead of creating all these details separately for each student, we can create a base object called "Course."
This object will hold the shared information. Both students can then inherit from this Course object, meaning they'll automatically get the course details, but they can also add their own unique attributes, like their name, student ID, and individual grades.
let course = {
courseName: "Introduction to Programming",
instructor: "Dr. Smith",
schedule: "Monday & Wednesday, 10 AM - 12 PM"
};
let student1 = {
name: "John Mark",
studentID: "S12345",
grade: "A"
};
let student2 = {
name: "Jane Doe",
studentID: "S67890",
grade: "B+"
};
student1.__proto__ = course;
student2.__proto__ = course;
console.log(student1.name);
console.log(student1.courseName);
console.log(student1.instructor);
console.log(student1.grade);
console.log(student2.name);
console.log(student2.courseName);
console.log(student2.instructor);
console.log(student2.grade);
The `student1` and `student2` objects represent individual students' properties (name, student ID, and grade), but they inherit the shared course details from the course object we created.
For us to inherit properties from the course object that contains the details shared by both students, we use the `__proto__` property. The `__proto__` property is the key that links an object to its prototype. This simply means that when we try to access the course properties for any student in our console, we won’t get an undefined value like the one we had in our first code example. Instead, the student will inherit the course details through the prototype.
Output:
JavaScript provided a standard way to implement prototypal inheritance and ES5 introduced two of the different methods such as `Object.create()` and `Object.getPrototypeOf()`. I mentioned the `__proto__` property being the old way to implement prototypal inheritance
Object.create() Method
This method creates a new object that inherits from another object's prototype. It takes an object as an argument and returns a new object with that specified object set as its prototype.
Let’s check out a simple code example :
const course = {
courseName: "Introduction to Programming",
instructor: "Dr. Smith",
schedule: "Monday & Wednesday, 10 AM - 12 PM"
};
const student = Object.create(course);
student.name = "John Mark";
student.studentID = "S12345";
student.grade = "A";
console.log(student.courseName);
console.log(student.name);
Object.setPrototypeOf()
The `Object.getPrototypeOf()` method lets you check what an object’s prototype is or what it’s inheriting from. It's like asking, "Who is this object's parent or base?”
let course = {
courseName: "Introduction to Programming",
instructor: "Dr. Smith"
};
let student = Object.create(course);
student.name = "John Mark";
student.studentID = "S12345";
console.log(Object.getPrototypeOf(student));
Output:
Constructor Function
Constructor functions in JavaScript are special functions used to create and set up objects. When you use the `new` keyword with a constructor function, it creates a new object, gives it specific properties, and connects it to a prototype, which is like a template for shared features. The main advantage is that each object gets its own unique properties, but they can also share common methods or data through the prototype.
function Student(name, studentID, grade) {
this.name = name;
this.studentID = studentID;
this.grade = grade;
}
Student.prototype.courseName = "Introduction to Programming";
Student.prototype.instructor = "Dr. Smith";
Student.prototype.schedule = "Monday & Wednesday, 10 AM - 12 PM";
let student1 = new Student("John Mark", "S12345", "A");
let student2 = new Student("Jane Doe", "S67890", "B+");
console.log(student1.name);
console.log(student1.courseName);
console.log(student2.name);
console.log(student2.courseName);
In the earlier example, we used `__proto__` to link individual students to the shared Course object, giving them access to common properties like the course name and instructor.
With constructor functions, we can achieve the same thing in a more formal way. Instead of manually linking objects, we create a constructor for students, and they automatically inherit shared properties from the prototype. This is a cleaner and more scalable way to create multiple objects with shared behaviors.
The constructor function was commonly used before ES6 introduced classes. While it still works perfectly fine today, many developers now prefer the easy class syntax that came with ES6.
class Student {
constructor(name, studentID, grade) {
this.name = name;
this.studentID = studentID;
this.grade = grade;
}
}
Student.prototype.courseName = "Introduction to Programming";
Student.prototype.instructor = "Dr. Smith";
Student.prototype.schedule = "Monday & Wednesday, 10 AM - 12 PM";
let student1 = new Student("John Mark", "S12345", "A");
let student2 = new Student("Jane Doe", "S67890", "B+");
console.log(student1.name);
console.log(student1.courseName);
console.log(student2.name);
console.log(student2.courseName);
This class syntax is more modern, cleaner, and easier to read while still achieving the same functionality as your constructor function.
Prototypal Inheritance is Important for the following reasons:
Objects can share features through a prototype instead of repeating code, making everything more efficient.
Shared methods and properties are kept in one place, which saves memory when you create multiple objects.
If you update something in the prototype, all the objects linked to it get updated automatically.
It keeps your code clean and reusable.
Conclusion
Prototypal inheritance is a good feature in JavaScript that makes object-oriented programming more flexible. It might seem a little unfamiliar, especially if you're used to classical inheritance in other languages, but once you understand once you understand the prototype chain, constructor functions, and how inheritance works in JavaScript, it's key to writing solid JavaScript.
Jscrambler
The leader in client-side Web security. With Jscrambler, JavaScript applications become self-defensive and capable of detecting and blocking client-side attacks like Magecart.
View All ArticlesMust read next
12 Useful JavaScript Newsletters
With so much happening in the JS ecosystem, it's not easy to stay on top of things. Here are 12 newsletters to bring the best news straight to your inbox.
February 10, 2022 | By Jscrambler | 5 min read
Enhancing JavaScript Security: Best Practices, Vulnerabilities, and Third-Party Risks
The widespread use of JavaScript makes it a focal point for cyber threats, exposing web applications to various security risks.
June 18, 2024 | By Antonello Semeraro | 10 min read