extends (JavaScript)
Learn extends (JavaScript) step by step with clear examples and exercises.
Title: Mastering JavaScript Inheritance with extends
Why This Matters
In this lesson, we'll dive into understanding the extends keyword in JavaScript, a crucial concept for structuring complex code and building reusable classes. You'll learn how to create child classes that inherit properties and methods from parent classes, making your code more modular, maintainable, and efficient. This skill is essential for tackling real-world programming challenges, acing coding interviews, and debugging common errors in large projects.
Prerequisites
To follow along with this lesson, you should be comfortable with the following:
- Basic JavaScript syntax, including variables, functions, loops, and conditional statements
- Understanding of objects and their properties and methods
- Familiarity with classes and constructors in JavaScript
Core Concept
The extends keyword is used in class declarations or expressions to create a child class that inherits from another class (the parent class). The child class can access and override the properties and methods of its parent class, making it easier to reuse code and avoid duplication.
Here's an example of creating a child class that extends a parent class:
class ParentClass {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello, I am ${this.name}`);
}
}
class ChildClass extends ParentClass {
constructor(name, occupation) {
super(name); // Call the parent class's constructor and pass `name` as an argument
this.occupation = occupation;
}
introduce() {
console.log(`Hi there! I am ${this.name}, a ${this.occupation}`);
}
}
In the example above, we create a ParentClass with a constructor that accepts a name parameter and a greet() method. We then create a ChildClass that extends ParentClass. The child class has an additional occupation property and a new introduce() method. When creating instances of the child class, we call the parent class's constructor using the super() function and pass the name parameter.
Inheritance and the Prototype Chain
When you create an instance of a child class, it has access to both its own properties and methods as well as those inherited from its parent class through the prototype chain. The prototype chain is a mechanism that allows JavaScript objects to inherit properties and methods from other objects. Each object in JavaScript has an internal [[Prototype]] property that points to another object (its prototype). If an object doesn't have a specific property or method, JavaScript searches its prototype for it, moving up the prototype chain until it finds the property or method or reaches the end of the chain (Object.prototype).
Overriding Methods and Properties
You can override properties and methods in child classes by redefining them with the same name. When a child class has a method with the same name as a method in its parent class, the child class's version of the method will be called instead. Here's an example:
class ParentClass {
greet() {
console.log(`Hello from ParentClass`);
}
}
class ChildClass extends ParentClass {
greet() {
console.log(`Hello from ChildClass`);
}
}
const parent = new ParentClass();
parent.greet(); // Outputs: Hello from ParentClass
const child = new ChildClass();
child.greet(); // Outputs: Hello from ChildClass
In the example above, we override the greet() method in the ChildClass. When creating an instance of ParentClass, it calls its own greet() method, while when creating an instance of ChildClass, it calls the overridden greet() method.
Accessing Parent Class Properties and Methods
You can access parent class properties and methods in child classes using the super keyword. The super keyword is a reference to the parent class's constructor or an instance of the parent class, depending on the context. Here's an example:
class ParentClass {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello, I am ${this.name}`);
}
}
class ChildClass extends ParentClass {
constructor(name, occupation) {
super(name); // Call the parent class's constructor and pass `name` as an argument
this.occupation = occupation;
}
introduce() {
console.log(`Hi there! I am ${this.name}, a ${this.occupation}`);
super.greet(); // Call the parent class's greet method
}
}
In the example above, we call the super.greet() method in the introduce() method of the child class to invoke the parent class's greet() method.
Worked Example
Let's create a simple example that demonstrates inheritance with JavaScript classes:
class Animal {
constructor(name, legs) {
this.name = name;
this.legs = legs;
}
walk() {
console.log(`${this.name} is walking on ${this.legs} legs`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name, 4); // Call the parent class's constructor and pass `4` as an argument for legs
this.breed = breed;
}
bark() {
console.log("Woof woof!");
}
}
const myDog = new Dog("Rex", "Labrador");
myDog.walk(); // Outputs: Rex is walking on 4 legs
myDog.bark(); // Outputs: Woof woof!
In this example, we create a Animal class with a constructor that accepts a name and legs parameter and a walk() method. We then create a Dog class that extends Animal. The child class has an additional breed property and a new bark() method. When creating an instance of the Dog class, we call the parent class's constructor using the super() function and pass 4 as an argument for the number of legs.
Common Mistakes
- Forgetting to call super(): If you don't call
super()in a child class's constructor, it will throw an error because the child class doesn't have its own constructor. Make sure to callsuper()and pass any necessary arguments. - Using
newincorrectly: When overriding methods in child classes, be careful not to usenewwhen you don't need it. For example, if you override a method that doesn't return an object, you should remove thereturnkeyword and thenewkeyword when calling the parent class's method. - Confusing
this: In child classes, be aware of the different meanings ofthis. When usingsuper,thisrefers to the child class instance. However, if you call a method on an object that doesn't usesuper,thisrefers to the parent class instance. - Not understanding the prototype chain: Make sure you understand how the prototype chain works in JavaScript so you can effectively access and manipulate properties and methods across classes.
Practice Questions
- Create a
Vehicleclass with a constructor that accepts aname,wheels, andcolorparameter, and a method calleddrive(). Then create aCarclass that extendsVehicleand has an additional property calledmodel. Override thedrive()method in theCarclass to print a custom message. - Create a
Shapeclass with a constructor that accepts anameparameter, and a method calledarea(). Then create aRectangleclass that extendsShapeand has properties forwidthandheight. Override thearea()method in theRectangleclass to calculate the area of the rectangle. - Create an
Employeeclass with a constructor that accepts aname,salary, andpositionparameter, and methods calledraiseSalary()andgetDetails(). Then create aManagerclass that extendsEmployeeand has an additional property calledteamSize. Override theraiseSalary()method in theManagerclass to increase the manager's salary by 10% if their team size is greater than 5.
FAQ
--
- Can I extend multiple classes in JavaScript? Yes, you can use multiple inheritance in JavaScript using mixins or the prototype chain, but it's not as straightforward as single inheritance.
- What happens if a child class has a method with the same name as a method in its parent class but does something different? When a child class has a method with the same name as a method in its parent class, the child class's version of the method will be called instead. This is known as overriding.
- What is the difference between
extendsandimplementsin JavaScript? In JavaScript, there is noimplementskeyword like in some other languages. Instead, you use interfaces to define a contract for a class to follow, and then useextendsto inherit from classes that implement those interfaces. - Why should I use inheritance in my code? Inheritance can help make your code more modular, maintainable, and efficient by allowing you to reuse code across multiple classes. It also helps reduce duplication of logic and simplifies the organization of complex programs.