Inheritance With Super
Introduction: Building On What Already Exists
In our last lesson, we learned how to build a secure Account class using private fields and accessors. This is a great foundation, but in the real world, software often requires many different types of accounts. You might need a SavingsAccount that earns interest, a CheckingAccount with transaction fees, or a BusinessAccount with higher limits. If we were to write a completely new class for each of these, we would end up repeating the same code for the owner's name and the balance logic over and over again.
In this lesson, we will explore inheritance. Inheritance allows us to create a new class based on an existing one. We can take all the features of our original Account class and "specialize" them for a SavingsAccount. This helps us avoid duplication and makes our code much easier to maintain. By the end of this lesson, you will know how to link classes together so that they share behavior while still maintaining their own unique features.
Creating A Child Class With Extends
Initializing The Parent With Super()
When you create a child class and give it its own constructor, there is a very important rule you must follow: you must call super() before you can use the this keyword. The super function tells JavaScript to run the constructor of the parent class first. This ensures that the parent has a chance to set up its own properties, like the owner and the #balance, before the child class tries to add its own specific data.
If you try to use this before calling super(), your code will crash with a reference error. Once super() is called, you can then proceed to set up any properties that are unique to the child class, such as an interest rate.
In this example, the SavingsAccount constructor takes three arguments. It passes the owner and balance up to the Account constructor by calling super(owner, balance). After that is finished, it sets the private #interestRate property that only exists for savings accounts. This sequence ensures the entire object is built correctly from the ground up.
Inheriting Methods And Properties
One of the most powerful aspects of inheritance is that the child class can use methods defined in the parent class as if they were its own. In our SavingsAccount, we might want a method called applyInterest that calculates interest based on the current balance and adds it to the account. Because SavingsAccount inherits from Account, it can call the deposit method and use the balance getter defined in the parent.
This allows us to reuse logic that we have already tested and verified. We don't have to rewrite the math for how a deposit works; we simply "ask" the parent part of the object to handle it for us.
In the applyInterest method, we use this.balance to get the current amount of money. Even though balance is defined in the Account class, it is fully available here. Similarly, we call this.deposit(interest) to update the balance. This shows how the child class can build new, complex features by combining its own data with the tools provided by the parent.
Overriding Methods And Extending Behavior
Checking The Inheritance Chain With Instanceof
As your programs grow, you will often need to check what kind of object you are working with. As you recall from the first lesson, the instanceof operator is perfect for this. In the context of inheritance, it allows us to see the full lineage of an object: when a class inherits from another, an instance of the child class is also considered an instance of the parent class. This reflects the "is-a" relationship we discussed earlier.
This behavior is very useful when writing functions that can work with any type of account but might need special handling for specific types. JavaScript looks up the "inheritance chain" (or prototype chain) to see if the object was built from a specific blueprint or any of that blueprint's ancestors:
SavingsAccount.prototype -> Account.prototype -> Object.prototype
Output:
The output shows that our variable s is both a SavingsAccount and an Account. This confirms that inheritance is working correctly. It allows us to treat s as a general Account when we just care about balances and owners, or as a specific SavingsAccount when we want to calculate interest.
Summary And Practice Preview
In this lesson, we explored how inheritance allows us to build specialized classes without repeating code. We learned that the extends keyword connects a child class to a parent class. We discovered that the super() function is a mandatory tool for initializing parent data within a child's constructor. We also looked at how to override methods and use super.methodName() to enhance existing behavior rather than just replacing it. Finally, we revisited instanceof to verify that our objects correctly belong to their inheritance chains.
These concepts are the building blocks for creating complex systems where different objects share common traits. In the upcoming practice exercises, you will get hands-on experience creating your own specialized classes. You will practice using super() to pass data and overriding methods to customize how your objects behave. All the tools you need are already set up in your CodeSignal environment, so you can jump right into the code. Happy practicing!
