Javascript Fácil

Aprende Javascript en tu idioma

Lo nuevo en ECMAScript 2019

2019-02-09 Christian C. Salvadójavascript

Del 29 al 31 de enero se llevó a cabo la reunión número 68 del comité TC-39, en donde se discutieron las propuestas que serán incluidas en la version 2019 final de ECMAScript.

Mathias Bynens, miembro del comité TC-39 anunció el listado de las propuestas que fueron aprobadas y llegaron al Stage 4 para ser incluidas en la siguiente versión:


En este artículo exploraremos las más relevantes.

Tabla de contenidos

Métodos Array.prototype.flat y flatMap para Arrays

Los métodos flat y flatMap, nos permiten aplanar arreglos, en otras palabras si tenemos un arreglo el cual posea elementos que sean sub-arreglos, estos nos permiten generar un arreglo nuevo, el cual tendrá todos los sub-elementos en el primer nivel.

Por ejemplo:

const array1 = [1, 2, [3, 4]];

const array2 = array1.flat();
// [1, 2, 3, 4]

El método flat acepta un argumento, el cual es el nivel de profundidad. En el ejemplo anterior lo utilizamos sin argumento, por defecto la profundidad es 1.

Si necesitamos un aplanamiento a mayor profundidad, podemos pasar un valor y esto hará que se aplanen recursivamente los arreglos:

const array1 = [1, 2, [3, [ 4, 5]]];

const array2 = array1.flat(2);
// [1, 2, 3, 4, 5]

Debemos notar también que método excluye huecos o elementos vacíos en el arreglo:

const array1 = [1, 2, , , 3, 4];

const array2 = array2.flat();
// [1, 2, 3, 4]

El método flatMap nos permite combinar la funcionalidad de el método map y el aplanado del método flat. Normalmente map nos permite generar un arreglo nuevo, basado en el resultado de la aplicación una función a cada elemento del arreglo original. Con flatMap podemos retornar un sub-arreglo de cada elemento original, todos estos van a ser combinados en un solo arreglo al final.

Por ejemplo, imaginemos que tenemos un arreglo de “equipos”, cada equipo contiene una propiedad que es una lista de “jugadores”, si quisiéramos extraer a todos los jugadores de todos los equipos en un solo arreglo, lo podríamos hacer de la siguiente manera:

const jugadores = equipos.flatMap(e => e.jugadores)

La historia de esta propuesta es algo controversial, ya que inicialmente se había propuesto llamar al método Array.prototype.flatten, y resulta que este nombre ya había sido utilizado hace muchos años por la librería MooTools.

MooTools fue una librería muy popular hace tiempo y algunos sitios continúan usándola, siempre se destacó por la característica de aumentar los prototipos de objetos nativos, - una práctica muy mala - como en este caso Array.prototype.flatten.

Sin embargo, que MooTools implementara su propia version de flatten en el prototipo de Array no era realmente el problema, ya que asi como todos los demás métodos de Array.prototype pueden ser sobre-escritos.

Array.prototype.flatten = /* implementación de MooTools */

El problema es que MooTools internamente utilizaba el ciclo for-in en Array.prototype y esperaba encontrar estos métodos como propiedades enumerables y resulta que por defecto todos las propiedades nativas de Array.prototype definidas en la especificación son no enumerabes y el hecho de asignar un nuevo valor a ellas no las hace enumerables.

Finalmente, después de tanta discusión y bromas de cambiar el nombre del método a “smush”, todo esto se resuelve en la reunion de Mayo de 2018, en donde se decide renombrar flatten por flat.

Object.fromEntries

Este método se propone para ser la contraparte de Object.entries, acepta un iterable de pares en forma [key, valor] y retorna un objeto nuevo el cual contiene estas propiedades y valores correspondientes a los pares originales.

Por ejemplo:

const obj = {
  a: 1,
  b: 2,
  c: 3,
}

const entries = Object.entries(obj)
// [ ['a',1], ['b',2], ['c', 3]]

const obj2 = Object.fromEntries(entries)
// { a: 1, b: 2, c: 3}

La combinación de Object.entries y Object.fromEntries nos permiten hacer cosas muy interesantes, como por ejemplo, filtrar las propiedades de un objeto estilo Array.prototype.filter:

function filterObject(object, callback) {
  const filtered = Object.entries(object)
    .filter(([key, value]) => callback(key, value));
  return Object.fromEntries(filtered);
}

const usuario = {
  "id": 1,
  "name": "Leanne Graham",
  "username": "Bret",
  "email": "[email protected]",
  "address": {
    "street": "Kulas Light",
    "suite": "Apt. 556",
    //...
  },
  "phone": "1-770-736-8031 x56442",
  //....
}

filterObject(usuario, key => ['name', 'email', 'phone'].includes(key))
/*
{
  name: "Leanne Graham",
  email: "[email protected]",
  phone: "1-770-736-8031 x56442"
}
*/

Y muchas cosas mas, podríamos replicar otras funciones de arreglos, por ejemplo Array.prototype.map pero para objetos, invertir propiedades/valores, etc…

Métodos String.prototype.trimStart y trimEnd

Los métodos trimStar y trimEnd son simplemente complementarios al método trim introducido en ECMAScript 2015 (ES6).

trimStar simplemente elimina espacios en blanco al inicio de una cadena de caracteres:

const cadena = '      hola mundo'.trimStart()
// 'hola mundo'

Y trimEnd elimina espacios en blanco al final de una cadena de caracteres:

const cadena = 'hola mundo      '.trimEnd()
// 'hola mundo'

Es importante notar que dado que las cadenas de caracteres son tipos primitivos, por lo tanto son inmutables y estos métodos retornan siempre cadenas nuevas.

Symbol.prototype.description

Normalmente durante la creación de un símbolo se puede especificar una descripción para efectos de depuración, pero no había forma mas que llamando al método toString para obtener esta descripción de vuelta, y el resultado incluía la palabra Symbol y paréntesis, por ejemplo:

const prueba = Symbol('prueba')

prueba.toString()
// "Symbol(prueba)"

Esta propuesta permite exponer la descripción del símbolo por medio de la propiedad description:

const prueba = Symbol('prueba')

prueba.description
// "prueba"

Catch con identificador opcional

Esta propuesta hace un cambio en la gramática de Javascript, permitiendo la omisión del identificador en el bloque de catch, el cual era requerido por la sintaxis especifica de esta gramática.

Normalmente siempre teníamos que definir un identificador en el bloque catch:

try {
  /*...*/
  } catch(error) {}

Ahora el bloque catch ya no requerirá el identificador:

try { } catch {}

En mi experiencia, usualmente no deseamos ignorar errores, pero hay ciertos casos en los cuales es valido, por ejemplo:

  • Cuando queremos probar alguna si alguna característica esta implementada:
let implementada;
try {
    usarCaracteristicaX();
    implementada = true;
} catch {
    implementada = false;
}

Deseamos parsear una cadena de JSON potencialmente malformado:

let resultado = valorPorDefecto;
try {
  resultado = JSON.parse(jsonPotencialmenteMalformado);
} catch {}

Acceder directamente a propiedades anidadas que podrían no existir, evitando chequear cada nivel:

//...
  let calle = 'N/D'
  try {
    calle = data.usuario.direccion.calle
  } catch {}
// ...

// En vez de:

const calle = data && data.usuario &&
              data.usuario.direccion &&
              data.usuario.direccion.calle

Relacionado:

JSON superset de ECMAScript

La propuesta JSON superset de ECMAScript agrega la capacidad a cadenas de texto literales, para contener dos caracteres que hasta la fecha no eran validos para Javascript, pero lo eran para el standard JSON (ECMA-404).

Los caracteres son:

  • U+2028 LINE SEPARATOR
  • U+2029 PARAGRAPH SEPARATOR

Para incluirlos en una cadena de caracteres, teníamos que hacerlo por medio de una secuencia de escape:

const cadena = '\u2028'
cadena.charAt(0) // "\u2028"

La inclusión del carácter real en una cadena producía un error sintáctico:

const evaluarCadena = '"\u2028"'
eval(evaluarCadena)
// SyntaxError: "" string literal contains an unescaped line break

Dado que el estándar de JSON ya intuía estos caracteres, se decidió quitar esta limitación en la gramática de literales de cadenas de caracteres.

Revisión a Function.prototype.toString

En esta propuesta, se hace una revision al método Function.prototype.toString, entre los puntos mas relevantes, se encuentran:

  • Funciones definidas en Javascript deberán producir exactamente el código fuente original, incluyendo espacios en blanco y comentarios:
function /* comentario */ prueba () { /* otro comentario */ }

// Antes:
prueba.toString();
// "function prueba() {}"

// Ahora:
foo.toString();
// "function /* comentario */ prueba () { /* otro comentario */ }"
  • Estandarizar la representación en cadena de caracteres de funciones built-in y de objetos del entorno:
Object.create.toString()
// "function create() { [native code] }"

alert.toString()
// "function alert() { [native code] }"

Suscríbete a nuestro boletín

Mantente al tanto de nuestras últimas noticias, cursos interactivos y artículos.

Loading...
Javascript Fácil

Chrisitan C. Salvadó es un desarrollador full stack especializado en Javascript y tecnologías web