Extending Class without `extends`


This is a follow-up blog to my recent one on How Everything in JS is an Object
.
I have already discussed what classes are and how they work under the hood in JavaScript.
If you haven't checked it out, feel free to do so, as it will help you understand this blog better.
In this post, we will look into an interesting question: How can we extend a class without using the extends
keyword?
Before diving into this question, let’s first have a fundamental understanding of what class
and extends
are.
Class and Extends
The concept of a class primarily comes from the Object-Oriented Programming
(OOP) paradigm. What is OOP? Let me briefly explain that too.
OOP (Object-Oriented Programming)
OOP is a programming paradigm — a way of writing code where you relate items to the real world. It is the core behind some languages like Java and C++.
In OOP, everything is an object. An object is derived from real-world entities that have properties and functions. For instance, a car has properties like color, model, and functionalities like accelerate
, brake
, etc. Hence, a car is considered an object.
The Class
here acts as a blueprint for the car object. Now, what does that mean?
Well, let’s take the example of the Thar
from Mahindra
. If you look at any Thar of the same model, you would find a common structure and build (unless modified).
So, there might be some guidelines and rules while manufacturing the Thar
that ensure it has a common structure and build, right?
Well, in OOP, these rules and guidelines that decide the properties and functionalities of objects are called Classes
. So objects are made from classes, and classes define how objects are created and what they should contain.
Now that we understand classes and objects, let’s briefly look at the four pillars of OOP.
Four Pillars of OOP
The four main pillars are Polymorphism
, Inheritance
, Abstraction
, and Encapsulation
.
While not all of these pillars are necessary for this blog, let me give you a brief idea of what they mean:
Polymorphism: Polymorphism refers to a single function taking multiple forms for different kinds of objects. For example, a
speak()
function can produce different outputs depending on whether it's called on a Dog or a Cat.Abstraction: Abstraction refers to hiding the internal implementation of code. For instance, using
Math.min()
in JS. You know what it does, but the internal implementation is hidden.Encapsulation: Encapsulation refers to wrapping code into a single function while restricting access to certain parts of it. For example,
setPrototypeOf
andgetPrototypeOf
are used to restrict direct access to the[[Prototype]]
property on objects.Inheritance: Inheritance refers to inheriting properties and functionality from a parent class. For example, a
Dog
class being inherited from anAnimal
class.
You can look up these concepts in more detail, but for now, we will focus on the Inheritance
part.
Extends = Inheritance
Yes, the extends
keyword represents the concept of inheritance
in OOP. It helps inherit the properties and functionality of a parent class. But, you may ask: Why do we need the properties of one class in another? What is the use of it?
Let’s understand this through a real-world example.
Let us continue with an example of Thar.
The Thar is one of the vehicles Mahindra manufactures, but there are other vehicles too, right?
Hence, we can make a base class (parent class) and put all the common properties, like the brand name Mahindra
, and functionalities like brake
, accelerate
, etc., there.
Now for every other vehicle manufactured by Mahindra you can extend this class MahindraVehicles and hence you don’t have to define the brand name in each and every of them.
class MahindraVehicles {
constructor(brand) {
this.brand = brand;
}
accelerate() {
// accelerate functionality here
}
}
class Thar extends MahindraVehicles {
// Some functionality here
constructor(model, brand) {
super(brand)
this.model = model;
}
}
class Scorpio extends MahindraVehicles {
// Additional functionality for Scorpio
constructor(model, brand) {
super(brand)
this.model = model;
}
offRoad() {
console.log("Scorpio is excellent for off-road adventures!");
}
}
You see two major things here: the
super
keyword and theconstructor
function. Let’s understand them.
Understanding Super keyword
Any word that is reserved by the programming language itself is known as a keyword. Super
is a major keyword that enables inheritance. It’s also present in languages like Java and is a significant feature of inheritance in the OOP paradigm.
Purpose: The super
keyword allows the child class to pass its properties to the parent class. It is particularly useful when we want to initialize the constructor properties of the parent class directly from the child class.
Now let's understand the constructor functions.
Constructor Function and Classes
A constructor function in a class is a function that is automatically called whenever a new object is created from the class. The constructor
keyword is used to make the constructor function in a class, as shown in the above code.
If you want to initialize the properties of the parent constructor
function from child class itself, you would use the super
keyword.
class MahindraVehicles {
constructor(name, brand) {
this.name = name;
this.brand = brand;
}
}
class Thar extends MahindraVehicles {
// Some functionality here
constructor(name, brand, model) {
super(name, brand)
this.model = model
}
}
Classes Before ES6
Before the ES6 version of JavaScript, there was no concept of classes. To achieve Inheritance
, we used the native prototypal Inheritance
(explained in my previous blog). However, with the ES6 version, JavaScript introduced the concept of Class
, as OOP became quite popular.
Since classes are part of OOP, JS also introduced the extends
keyword to maintain familiarity with OOP among programmers.
Under the hood, these classes and the extends
keyword are using functions only, so they are called syntactic sugar
. To extend a class without the extends
keyword, it’s necessary to understand a few things:
JavaScript follows
prototypal inheritance
, meaning every object in JS has a[[Prototype]]
property that points to another object.This
prototype chain
ends when the last[[Prototype]]
points toObject
, hence everything in JS is an object.It ends there because the
[[Prototype]]
ofObject
points tonull
.
All of these concepts are explained in detail in my previous blog.
Extending a Class without extends
Now that we understand the basic concepts, the constructor function, and the super
keyword, let’s try answering the initial question: How can we extend a class without using the extends
keyword?
We will be utilizing the same concept of prototypal inheritance. As discussed, every object in JS has a [[Prototype]]
property attached to it internally. In the case of classes, this property resides under the .prototype
property, along with the constructor.
Hence, to give one class the methods and properties of another, we just need to add the parent class to the [[Prototype]]
property of the child class. Let’s see that in action:
Now, you can access all the methods present in MahindraVehicles
, like accelerate()
.
So what’s the problem here ? The problem is you cannot use or access the name and brand
of the parent class as you haven’t declared/ constructed it yet. You cannot do the following thing without using the super
keyword and passing the name and brand.
But the catch here is you cannot use
super
keyword without using theextends
keyword on a class. So can’t we mimic the super keyword ? You can but you must go to the internalConstructor function
to mimic the whole class functioning.
Mimicking super
without super
keyword
Now you may wonder, Can we mimic the super
keyword too? Well, technically you can. But to mimic the super
keyword, you must make the constructor function itself.
The
MahindraVehicles.call()
mimics the use ofsuper
keyword here.
Can’t you mimic super
in the class itself?
- No, because you cannot call the constructor functions for classes without creating objects using
.new
. Hence, we were given thesuper
keyword to simplify this.
Conclusion
In this blog, we’ve explored an essential concept of classes and their inner workings in JavaScript, while also diving into the principles of OOP. We’ve learned how the extends
keyword and classes as a whole acts as syntactic sugar
, how to mimic the super
keyword, and what role it plays in inheritance, all explained with practical examples.
If you found this blog helpful, feel free to like it and subscribe to my newsletter. You’ll receive more insights like this, delivered in an easy-to-understand format! Stay tuned, as we will soon be diving deeper into JavaScript internals.
Subscribe to my newsletter
Read articles from Rohit directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Rohit
Rohit
Just a curious child exploring tech