Seleccionar página
Como conclusión a nuestra serie de artículos donde hemos explicado algunas posibles extensiones de Map y Set, os proponemos dar un repaso a otras propuestas ampliación del estándar de estos objetos y a librerías bastante completas y probadas que extienden estos objetos con nuevas funcionalidades.

Propuestas de ampliación del estándar (TC39)

Vamos a revisar las propuestas que se han presentado ante el comité TC39, el organismo dedicado a la estandarización de Javascript, para ampliar los objetos Set y Map.

Extensión de Set (Stage 2)

https://github.com/tc39/proposal-set-methods

A la fecha de publicación de este artículo hay una propuesta al TC39 para ampliar el objeto Set con nuevos métodos basados en la gestión de conjuntos. Esta propuesta está en estado 2 y todavía pueden sufrir bastantes cambios, incluso no llegar a ser parte del estándar, pero nos ofrece una perspectiva sobre lo que se están plateando para un futuro más o menos próximo.

Si no queremos esperar a que se estandaricen y generalicen estas funciones, podemos crear una clase heredada de Set que incluya los mismos métodos que esta propuesta incluye:

class ExtSet extends Set {

  intersection (iterable) {
    const newSet = new (Object.getPrototypeOf (this).constructor) ();
    for (let e of iterable) {
      if (this.has (e)) {
        newSet.add (e);
      }
    }
    return newSet;
  }

  union (iterable) {
    const newSet = new (Object.getPrototypeOf (this).constructor) (this);
    for (let e of iterable) {
      newSet.add (e);
    }
    return newSet;
  }

  difference (iterable) {
    const newSet = new (Object.getPrototypeOf (this).constructor) (this);
    for (let e of iterable) {
      newSet.delete (e);
    }
    return newSet;
  }

  symmetricDifference (iterable) {
    const newSet = new (Object.getPrototypeOf (this).constructor) (this);
    for (let e of iterable) {
      newSet.delete (e) || newSet.add (e);
    }
    return newSet;
  }

  isSubsetOf (iterable) {
    if (typeof iterable.has !== 'function') {
      iterable = new Set (iterable);
    }
    for (let e of this) {
      if (!iterable.has (e)) {
        return false;
      }
    }
    return true;
  }

  isSupersetOf (iterable) {
    for (let e of iterable) {
      if (!this.has (e)) {
        return false;
      }
    }
    return true;
  }

  isDisjointFrom (iterable) {
    for (let e of iterable) {
      if (this.has (e)) {
        return false;
      }
    }
    return true;
  }

}

Extensión de Map y Set (Stage 1)

https://github.com/tc39/proposal-collection-methods

Hay otra propuesta al TC39 para ampliar los objetos Map y Set con nuevos métodos similares a los que encontramos en Array. Al está en estado 1 es muy difícil saber si serán finalmente parte del estándar o se producirán cambios muy sustanciales.

Aquí incluimos varias de estas funcionalidades, similares a las que provee Array, en una clase que hereda de Map:

class ExtMap extends Map {

  every (callback, thisArg) {
    const iterator = this[ Symbol.iterator ] ();
    let step;
    while (!(step = iterator.next ()).done) {
      if (!callback.call (thisArg || this, step.value[ 1 ], step.value[ 0 ], this)) {
        return false;
      }
    }
    return true;
  }

  filter (callback, thisArg) {
    const newMap   = new (Object.getPrototypeOf (this).constructor) ();
    const iterator = this[ Symbol.iterator ] ();
    let step;
    while (!(step = iterator.next ()).done) {
      if (callback.call (thisArg || this, step.value[ 1 ], step.value[ 0 ], this)) {
        newMap.set (step.value[ 0 ], step.value[ 1 ]);
      }
    }
    return newMap;
  }

  find (callback, thisArg) {
    for (let element of this) {
      if (callback.call (thisArg || this, element[ 1 ], element[ 0 ], this)) {
        return element;
      }
    }
  }

  findKey (callback, thisArg) {
    for (let element of this) {
      if (callback.call (thisArg || this, element[ 1 ], element[ 0 ], this)) {
        return element[ 0 ];
      }
    }
  }

  map (callback, thisArg) {
    const newMap   = new (Object.getPrototypeOf (this).constructor) ();
    const iterator = this[ Symbol.iterator ] ();
    let step;
    while (!(step = iterator.next ()).done) {
      let result = callback.call (thisArg || this, step.value[ 1 ], step.value[ 0 ], this);
      newMap.set (result[ 0 ], result[ 1 ]);
    }
    return newMap;
  }

  reduce (callback, initialValue) {
    const iterator = this[ Symbol.iterator ] ();
    let step;
    while (!(step = iterator.next ()).done) {
      initialValue = callback(initialValue, step.value[ 1 ], step.value[ 0 ], this);
    }
    return initialValue;
  }

  some (callback, thisArg) {
    const iterator = this[ Symbol.iterator ] ();
    let step;
    while (!(step = iterator.next ()).done) {
      if (callback.call (thisArg || this, step.value[ 1 ], step.value[ 0 ], this)) {
        return true;
      }
    }
    return false;
  }
}

Librerías

Hay un buen número de librerías y paquetes que amplían y complementan la funcionalidad de Map y Set. Aquí recogemos dos de las más populares e interesantes, pero os animamos a explorar otras opciones más allá de estas que os proponemos.

Inmutable

https://immutable-js.github.io/immutable-js/

Esta interesante librería se basa en la idea utilizar sólo datos inmutables, es decir, que no se pueden cambiar una vez creados, lo que lleva a un desarrollo mucho más simple y confiable. Por ello todas las funciones que producirían cambios en los datos generan nuevos objetos con los datos actualizados, pero nunca modifican los datos originales.

Immutable proporciona muchas estructuras de datos persistentes e inmutables que incluyen: List, Stack, Map, OrderedMap, Set, OrderedSet, Record, una versión lazy de Seq, etc.

Immutable es una librería extremadamente popular y tiene millones de descargas semanales en NPM, dando soporte tanto a Javascript como a Flow y Typescript, con una documentación bastante completa.

Collections JS

http://www.collectionsjs.com/

Esta librería proporciona una completa implementación para manejar colecciones en Javascript, con características bastante útiles. Estas colecciones proporcionan alternativas a los objetos estándar de Javascript.

CollectionsJS incluye la capacidad de observar todos los cambios y tener una interfaz común en cada colección, implementando métodos genéricos, muchos ya conocidos de Array, y otros nuevos que complementan la funcionalidad.

Ofrece implementaciones de List, Object, Map, FastMap, LruMap, LfuMap, SortedMap, SortedArrayMap, Dict, MultiMap, WeakMap, Deque, Array, Set, FastSet, LruSet, LfuSet, SortedSet, SortedArraySet, SortedArray, Heap e Iterator.

CollectionJS es una librería muy probada y ampliamente difundida, por lo que su uso es bastante recomendable. Su documentación es muy fácil de consultar, a pesar de la gran cantidad de objetos y métodos que incluye la librería.

Conclusiones

En esta serie de artículos hemos mostrado algunas de las capacidades que podemos añadir a Map y Set para que se comporten de la forma que nos interesa en cada caso. Las posibilidades son prácticamente infinitas. Podemos manejar estas simples estructuras de datos con nuevas funcionalidades por medio de la herencia nos abre una vía de exploración muy atractiva que os invitamos a continuar.

Como se puede ver, ya hay librerías bastante completas que han ampliado y ajustado estos objetos estándar a diferentes contextos y funcionalidades. Construir estas funcionalidades por nosotros mismos tampoco es complicado y hemos aportado diferentes ejemplos de ello. Mantener nuestros datos en estructuras bien formadas y organizadas nos ofrece un gran control sobre los mismos, sin que por ello tengamos que perder necesariamente el rendimiento de las soluciones más simples.

Esperamos haber provocado cierta curiosidad en vosotros y exploréis las capacidades de extensión de Map y Set.

Novedades

customElements a fondo

Vamos a dar repaso general a customElements y todos sus métodos. Esta es una pieza clave para la creación de Custom Tag, uno de los pilares de los Web Components. Hemos intentado empezar por lo más básico e ir avanzando hasta describir algunos de sus comportamientos más complejos, además de describir algunas de las características más importantes de los Web Components.

Uso de jsRPC en una aplicación de ejemplo

Para poder comprender mejor cómo podemos utilizar la librería jsRPC hemos creado una aplicación de ejemplo en la que hemos utilizado el modelo RPC para que el front invoque funciones del servidor y para que los diferentes microservicios invoquen de forma remota funciones entre ellos.

Un completo sistema RPC en Javascript con sólo 100 líneas

La aparición de gRPC de Google ha hecho que vuelva a ponerse de moda los sistemas de Remote Procedure Calls. La mayoría de las implementaciones de RPC se han ajustado muy poco a las características idiomáticas de Javascript. Con jsRPC mostramos cómo desarrollar un completo sistema RPC utilizando las características de Javascript.

Usar correctamente el método sort()

En general no se hace un uso habitual del método .sort() de los Array y muchas ocasiones se desconoce cómo hacer funcionar este método de forma correcta. En este artículo os contaremos cómo funciona y cómo sacar partido a sus características.