Extender múltiples clases en JavaScript

Waqar Aslam 12 octubre 2023
  1. Enfoque de composición para extender múltiples clases en JavaScript
  2. Enfoque de delegación de comportamiento para extender varias clases en JavaScript
Extender múltiples clases en JavaScript

JavaScript no tiene un mecanismo incorporado para extender múltiples clases. Sin embargo, para lograr un efecto similar de herencias múltiples en JavaScript, use técnicas llamadas composición y delegación de comportamiento.

Enfoque de composición para extender múltiples clases en JavaScript

Con la composición, en lugar de heredar propiedades y métodos de varias clases, puede crear una instancia de cada clase, almacenarla como una nueva propiedad de clase y luego delegar las llamadas de métodos a las instancias correspondientes.

Es importante tener en cuenta que con este enfoque, tiene más control sobre el comportamiento de la clase; puede acceder a las propiedades y métodos de la clase compuesta y anular métodos si es necesario.

Implementación para extender múltiples clases

En el siguiente ejemplo, la clase C tiene una instancia de la clase A y la clase B como propiedades y delega las llamadas al método a las instancias correspondientes. De esta forma, la clase C puede acceder a los métodos tanto de la clase A como de la clase B.

La clase A tiene un único método llamado métodoA que envía un mensaje Clase A: métodoA llamado a la consola cuando se le llama. La clase B tiene un único método llamado métodoB que envía un mensaje Clase B: métodoB llamado a la consola cuando se le llama.

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

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

La clase C usa el patrón de composición para lograr un efecto similar de herencias múltiples. El constructor crea instancias de clase A y clase B y las almacena como propiedades a y b, respectivamente.

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

La clase C tiene dos métodos, métodoA y métodoB, que realizan operaciones adicionales antes y después de llamar a los métodos correspondientes de las clases A y 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');
}

Cuando se ejecutan las dos últimas líneas, crean una instancia de la clase C y luego llaman a su métodoA() y métodoB().

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

Código fuente:

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();

Producción:

enfoque de composición

Enfoque de delegación de comportamiento para extender varias clases en JavaScript

Otra variación de este enfoque es usar la “delegación de comportamiento” donde, en lugar de almacenar instancias de la clase compuesta, delega directamente las llamadas al método a una propiedad en la clase compuesta.

Implementación para extender múltiples clases

Cuando se llama al métodoA de la clase C, primero muestra un mensaje Clase C: operación adicional antes de llamar al métodoA a la consola, luego llama al métodoA de la clase A usando A.prototype.methodA.call (esto);, esto generará Clase A: método A llamado a la consola.

Finalmente, emite un mensaje Clase C: operación adicional después de llamar al método A a la consola.

De manera similar, cuando se llama al método B de la clase C, primero muestra un mensaje Clase C: operación adicional antes de llamar al método B a la consola, luego llama al método B de la clase B usando B.prototype.methodB.call(this);, esto generará Clase B: métodoB llamado a la consola.

Finalmente, emite un mensaje Clase C: operación adicional después de llamar al método B a la consola.

De esta forma, la clase C puede acceder a los métodos tanto de la clase A como de la clase B y agregar algunas operaciones adicionales a los métodos sin modificar las clases originales.

Es importante notar que, en este caso, la clase C no tiene instancias de A y B. En cambio, usa el método call para invocar los métodos de A y B en el contexto de la clase C.

Código fuente:

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();

Producción:

enfoque de delegación

Este enfoque es más eficiente en memoria que la composición pero menos flexible porque no puede acceder a las propiedades de la clase compuesta.

Como puede ver, en ambos casos, la clase C puede agregar algunas operaciones adicionales a los métodos de la clase A y la clase B sin modificar las clases originales. De esta manera, puede mantener las clases originales limpias y separadas y agregar funciones específicas a la nueva clase C.

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

Artículo relacionado - JavaScript Class