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

Aplicaciones JAMStack, SEO friendly y escalables con NextJS

Aplicaciones JAMStack, SEO friendly y escalables con NextJS

En esta charla de Madrid JS, Rafael Ventura nos describe las funcionalidades clave de NextJS, nos muestra en vivo cómo desarrollar una completa aplicación JAMStack con Server Side Rendering (SSR) y Static Site Generation (SSG) y termina mostrando como publicar esta aplicación en Vercel.

Stencil JS: mejora el Time To Market de tu producto, por Rubén Aguilera

Stencil JS: mejora el Time To Market de tu producto, por Rubén Aguilera

En esta charla Rubén Aguilera nos cuenta los problemas que tienen muchas empresas a la hora de sacar productos accesibles, vistosos y usables en el Time To Market que requiere Negocio y cómo podemos minimizar este tiempo gracias al DevUI con StencilJS para adecuar una aplicación de Angular a las exigencias del mercado en tiempo record.

Svelte JS: por qué dedicarle tiempo, por Jesús Cuesta

Svelte JS: por qué dedicarle tiempo, por Jesús Cuesta

Jesús Cuesta cuenta qué es Svelte, para qué sirve, cómo compite contra aplicaciones construidas con React o Vuejs, si sirve para desarrollar web components, si la curva de aprendizaje es muy alta, y sobre todo si está suficiente maduro para utilizarlo. Si quieres conocer Svelte no puedes perderte esta introducción.

Javascript: 25 aniversario

Javascript: 25 aniversario

25 años con Javascript han dado para mucho. Pero todavía queda mucho para este lenguaje de programación.