Mixins en JavaScript

Author
By Darío Rivera
Posted on 2022-03-12 in Javascript

Los mixins en JavaScript son un patrón de diseño ampliamente utilizado que te permite realizar programación horizontal disponibilizando funciones a través de varias clases u objetos. Vamos a ver un poco más a detalle este patrón con un ejemplo práctico.

Escenario

Supongamos que tenemos una clase que valida si un número es dígito.

class Digits {
  RegExpr = /^\d*$/;
  messages = {};

  constructor(value) {
    this.value = value;
  }

  isValid() {
    if (!this.value.match(this.RegExpr)) {
      this.messages.notDigits = 'The input must contain only digits';
      return false;
    }

    return true;
  }

  getMessages() {
    return this.messages;
  }
}

Para verificar si un string es numérico podríamos hacer algo como lo siguiente:

const digits = new Digits('a');
digits.isValid();
digits.getMessages();  // {notDigits: 'The input must contain only digits'}

Ahora bien, supongamos que tenemos otra clase que valida una cadena alfanumérica.

class Alnum {
  RegExpr = /^(\d|[a-zA-Z]|\s)*$/;
  messages = {};

  constructor(value) {
    this.value = value;
  }

  isValid() {
    if (!this.value.match(this.RegExpr)) {
      this.messages.notAlnum = 'The input contains characters which are non alphabetic and no digits';
      return false;
    }

    return true;
  }

  getMessages() {
    return this.messages;
  }
}

Para verificar si un string es alfanumérico podríamos hacer algo como lo siguiente:

const alnum = new Alnum('añ/45@');
alnum.isValid();
alnum.getMessages();

Uso de mixins

En el anterior ejemplo puedes notar que ambas clases utilizan el método getMessages(). En primera instancia uno podría pensar en crear una clase abstracta y extender estos dos validadores de ella. Sin embargo, este método es un poco más genérico y podría ser utilizado no solo en validadores sino en cualquier otro tipo de objetos. Es por esto, que la solución adecuada es que este comportamiento sea horizontal y no vertical.

Para lograr esto basta con quitar de cada clase el método getMessages() y crear el siguiente objeto.

const HasMessages = {
  getMessages() {
    return this.messages;
  },
};

Una vez hecho esto debemos asignar al prototype de cada clase dicho objeto.

Object.assign(Alnum.prototype, HasMessages);
Object.assign(Digits.prototype, HasMessages);

Si utilizas módulos ES en tu aplicación esta sentencia podría ir en cada archivo de clase justo antes del export. De esta manera estás asignando dicho método para ser utilizado por ambas clases sin repetir el código y permitiendo que sea utilizado en otro tipo de entidades.


Acerca de Darío Rivera

Author

Ingeniero de desarrollo en PlacetoPay , Medellín. Darío ha trabajado por más de 6 años en lenguajes de programación web especialmente en PHP. Creador del microframework DronePHP basado en Zend y Laravel.

Sólo aquellos que han alcanzado el éxito saben que siempre estuvo a un paso del momento en que pensaron renunciar.