How to Extend Multiple Classes in JavaScript

Waqar Aslam Feb 02, 2024
  1. Composition Approach to Extend Multiple Classes in JavaScript
  2. Behavioral Delegation Approach to Extend Multiple Classes in JavaScript
How to Extend Multiple Classes in JavaScript

JavaScript does not have a built-in mechanism for extending multiple classes. However, to achieve a similar effect of multiple inheritances in JavaScript, use techniques called composition and behavioral delegation.

Composition Approach to Extend Multiple Classes in JavaScript

With composition, instead of inheriting properties and methods from multiple classes, you can create an instance of each class, store it as a new class property, and then delegate the methods calls to the corresponding instances.

It’s important to note that with this approach, you have more control over the class’s behavior; you can access the properties and methods of the composed class and override methods if needed.

Implementation to Extend Multiple Classes

In the following example, class C has an instance of class A and class B as properties, and it delegates the method calls to the corresponding instances. This way, class C can access the methods of both class A and class B.

Class A has a single method called methodA that outputs a message Class A: methodA called to the console when called. Class B has a single method called methodB that outputs a message Class B: methodB called to the console when called.

class A {
  methodA() {
    console.log('Class A: methodA called');
  }
}

class B {
  methodB() {
    console.log('Class B: methodB called');
  }
}

Class C uses the composition pattern to achieve a similar effect of multiple inheritances. The constructor creates instances of class A and class B and stores them as properties a and b, respectively.

constructor() {
  this.a = new A();
  this.b = new B();
}

Class C has two methods, methodA and methodB, which perform additional operations before and after calling the corresponding methods of classes A and B.

methodA() {
  console.log('Class C: Additional operation before calling methodA');
  this.a.methodA();
  console.log('Class C: Additional operation after calling methodA');
}

methodB() {
  console.log('Class C: Additional operation before calling methodB');
  this.b.methodB();
  console.log('Class C: Additional operation after calling methodB');
}

When the last two lines are executed, they create an instance of class C and then call its methodA() and methodB().

const c = new C();
c.methodA();
c.methodB();

Source Code:

class A {
  methodA() {
    console.log('Class A: methodA called');
  }
}

class B {
  methodB() {
    console.log('Class B: methodB called');
  }
}

class C {
  constructor() {
    this.a = new A();
    this.b = new B();
  }

  methodA() {
    console.log("Class C: Additional operation before calling methodA");
    this.a.methodA();
    console.log("Class C: Additional operation after calling methodA");
  }

  methodB() {
    console.log("Class C: Additional operation before calling methodB");
    this.b.methodB();
    console.log("Class C: Additional operation after calling methodB");
  }
}

const c = new C();
c.methodA();
c.methodB();

Output:

composition approach

Behavioral Delegation Approach to Extend Multiple Classes in JavaScript

Another variation of this approach is to use behavioral delegation where instead of storing instances of the composed class, you directly delegate the method calls to a property on the composed class.

Implementation to Extend Multiple Classes

When the methodA of class C is called, it first outputs a message Class C: Additional operation before calling methodA to the console, then it calls the methodA of class A by using A.prototype.methodA.call(this);, this will output Class A: methodA called to the console.

Finally, it outputs a message Class C: Additional operation after calling methodA to the console.

Similarly, when the methodB of class C is called, it first outputs a message Class C: Additional operation before calling methodB to the console, then it calls the methodB of class B by using B.prototype.methodB.call(this);, this will output Class B: methodB called to the console.

Finally, it outputs a message Class C: Additional operation after calling methodB to the console.

This way, class C can access the methods of both class A and class B and add some additional operations to the methods without modifying the original classes.

It is important to notice that, in this case, class C doesn’t have instances of A and B. Instead, it uses the call method to invoke the methods of A and B in the context of class C.

Source Code:

class A {
  methodA() {
    console.log('Class A: methodA called');
  }
}

class B {
  methodB() {
    console.log('Class B: methodB called');
  }
}

class C {
  methodA() {
    console.log("Class C: Additional operation before calling methodA");
    A.prototype.methodA.call(this);
    console.log("Class C: Additional operation after calling methodA");
  }

  methodB() {
    console.log("Class C: Additional operation before calling methodB");
    B.prototype.methodB.call(this);
    console.log("Class C: Additional operation after calling methodB");
  }
}

const c = new C();
c.methodA();
c.methodB();

Output:

delegation approach

This approach is more memory efficient than composition but less flexible because it can’t access the properties of the composed class.

As you can see, in both cases, class C can add some additional operations to the methods of class A and class B without modifying the original classes. This way, you can keep the original classes clean and separated and added specific functionality to the new class C.

Author: Waqar Aslam
Waqar Aslam avatar Waqar Aslam avatar

I am Waqar having 5+ years of software engineering experience. I have been in the industry as a javascript web and mobile developer for 3 years working with multiple frameworks such as nodejs, react js, react native, Ionic, and angular js. After which I Switched to flutter mobile development. I have 2 years of experience building android and ios apps with flutter. For the backend, I have experience with rest APIs, Aws, and firebase. I have also written articles related to problem-solving and best practices in C, C++, Javascript, C#, and power shell.

LinkedIn

Related Article - JavaScript Class