JavaScript > Prototypes and Inheritance > Constructor Functions and Classes > super keyword

Using 'super' to Call Parent Class Constructor and Methods

This example demonstrates how to use the super keyword in JavaScript to call the constructor and methods of a parent class within a child class. Understanding super is crucial for effective inheritance and code reuse.

Base Class: Animal

This is the parent class, Animal. It has a constructor that takes a name argument and a speak method.

class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(`${this.name} makes a sound.`);
  }
}

Derived Class: Dog

This is the child class, Dog, which inherits from Animal. The constructor uses super(name) to call the Animal constructor and initialize the name property. It then adds its own breed property. The speak method also uses super.speak() to call the parent class's speak method before adding its own behavior.

class Dog extends Animal {
  constructor(name, breed) {
    super(name); // Call the constructor of the parent class (Animal)
    this.breed = breed;
  }

  speak() {
    super.speak(); // Call the speak method of the parent class
    console.log(`${this.name} barks!`);
  }
}

Creating Instances

This code creates instances of both the Animal and Dog classes. When dog.speak() is called, it first executes the Animal class's speak method via super.speak(), then executes its own code to print 'Buddy barks!'.

const animal = new Animal('Generic Animal');
animal.speak(); // Output: Generic Animal makes a sound.

const dog = new Dog('Buddy', 'Golden Retriever');
dog.speak(); // Output: Generic Animal makes a sound.
             //         Buddy barks!

Concepts Behind the Snippet

This snippet demonstrates the core concepts of inheritance in JavaScript, specifically using the super keyword. Inheritance allows you to create new classes based on existing classes, inheriting their properties and methods. super is used to access and call functions on an object's parent. It is crucial to call super() within the constructor of a child class before accessing this. This initializes the this context with the parent class properties.

Real-Life Use Case

Imagine building a UI library. You might have a base Component class with common functionality like rendering and event handling. Then, you could create specialized components like Button, TextInput, and Dropdown that inherit from Component. The super keyword would allow the specialized components to reuse the core rendering and event handling logic from the base class, while adding their own specific behaviors. For example, the Button might override the render method to add specific styling, calling super.render() first to maintain the basic component structure.

Best Practices

  • Always call super() in the constructor of a derived class if you are defining a constructor.
  • Ensure super() is called before accessing this within the constructor.
  • Use super.methodName() to call a method from the parent class when overriding it in the child class.
  • Avoid deeply nested inheritance hierarchies, as they can become difficult to manage and understand.

Interview Tip

Be prepared to explain the purpose of the super keyword and how it relates to inheritance. Also, understand the difference between calling super() in the constructor and calling super.methodName() when overriding a method. Explain why calling super() is necessary before accessing this within the constructor of a derived class. Be able to explain scenarios where using super improves code reusability and maintainability.

When to Use Them

Use inheritance and the super keyword when you have classes that share common properties and behaviors. It promotes code reuse and reduces redundancy. If you find yourself duplicating code across multiple classes, consider using inheritance to create a base class with the shared functionality.

Memory Footprint

Inheritance generally adds a small overhead to the memory footprint compared to simply duplicating code. Each instance of a derived class will contain a reference to its parent class's prototype. However, the benefits of code reuse and maintainability usually outweigh this slight increase in memory usage, especially in larger applications.

Alternatives

  • Composition: Instead of inheriting from a parent class, a class can contain instances of other classes and delegate responsibilities to them. This can lead to more flexible and loosely coupled designs.
  • Mixins: Mixins allow you to 'mix in' functionality from multiple objects into a single object. This can be useful for sharing code between classes that don't necessarily have an 'is-a' relationship.

Pros

  • Code Reusability: Inheritance promotes code reuse by allowing derived classes to inherit properties and methods from parent classes.
  • Organization: Inheritance helps organize code into a hierarchical structure, making it easier to understand and maintain.
  • Polymorphism: Inheritance enables polymorphism, allowing objects of different classes to be treated as objects of a common type.

Cons

  • Tight Coupling: Inheritance can create tight coupling between parent and child classes, making it difficult to modify the parent class without affecting the child classes.
  • Fragile Base Class Problem: Changes to the base class can inadvertently break derived classes.
  • Increased Complexity: Deep inheritance hierarchies can be difficult to understand and maintain.

FAQ

  • What happens if I don't call super() in the constructor of a derived class?

    If you don't call super() in the constructor of a derived class that has a constructor, you will get a ReferenceError. You must call super() before accessing this in the constructor to properly initialize the instance with the parent class's properties.
  • Can I call super() multiple times in a constructor?

    No, you should only call super() once in the constructor of a derived class. Calling it multiple times can lead to unexpected behavior and potentially corrupt the object's state.
  • What if the parent class doesn't have a constructor?

    If the parent class does not have a constructor, you don't need to call super() in the derived class's constructor. However, if you want to initialize properties defined in the parent's prototype, it's good practice to include a constructor and call super().