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

¿Qué pasa con import y los web components?

¿Qué pasa con import y los web components?

Uno de los más controvertidos pilares de los componentes web ha sido el HTML Import. Considerado en estos momentos como una funcionalidad discontinuada, debemos conocer como sacar el máximo partido la instrucción import de Javascipt para gestionar la carga de nuestros componentes.
Template a fondo

Template a fondo

Hay dos formas estándar de crear contenido en un componente de forma flexible: la etiqueta template, que se considera como uno de los pilares de los Web Components y las template string de Javascript, que son una buena alternativa para generar el Shadow DOM con interpolación de datos.
Light DOM a fondo

Light DOM a fondo

El Light DOM es un espacio compartido entre nuestro componente web y el DOM general, que podemos utilizar para insertar contenido o configurar nuestro componente. Es una muy interesante característica que debemos conocer.
Shadow DOM a fondo

Shadow DOM a fondo

Para que los componentes web no colisionen unos con otros es muy útil utilizar el Shadow DOM para aislar el DOM y el CSS de cada componente. Esta característica se puede aplicar también a elementos HTML sin necesidad de utilizar Custom Elements, pero es con estos donde cobra todo su potencial. Demos un repaso profundo a las capacidades del Shadow DOM.