Pular para o conteúdo principal

Combinadores de Promise

· Leitura de 5 minutos
Mathias Bynens ([@mathias](https://twitter.com/mathias))

Desde a introdução de promises no ES2015, o JavaScript suporta exatamente dois combinadores de promise: os métodos estáticos Promise.all e Promise.race.

Duas novas propostas estão atualmente passando pelo processo de padronização: Promise.allSettled e Promise.any. Com essas adições, haverá um total de quatro combinadores de promise no JavaScript, cada um possibilitando diferentes casos de uso.

`Array.prototype.flat` e `Array.prototype.flatMap`

· Leitura de 2 minutos
Mathias Bynens ([@mathias](https://twitter.com/mathias))

Array.prototype.flat

O array neste exemplo tem vários níveis de profundidade: contém um array que, por sua vez, contém outro array.

const array = [1, [2, [3]]];
// ^^^^^^^^^^^^^ array externo
// ^^^^^^^^ array interno
// ^^^ array mais interno

Array#flat retorna uma versão achatada de um array fornecido.

array.flat();
// → [1, 2, [3]]

// …é equivalente a:
array.flat(1);
// → [1, 2, [3]]

A profundidade padrão é 1, mas você pode passar qualquer número para achatar recursivamente até essa profundidade. Para continuar achatando recursivamente até o resultado não conter mais arrays aninhados, passamos Infinity.

// Achatar recursivamente até o array não conter mais arrays aninhados:
array.flat(Infinity);
// → [1, 2, 3]

Por que esse método é chamado de Array.prototype.flat e não Array.prototype.flatten? Leia nosso artigo sobre #SmooshGate para descobrir!

Array.prototype.flatMap

Aqui está outro exemplo. Temos uma função duplicate que recebe um valor e retorna um array que contém esse valor duas vezes. Se aplicarmos duplicate a cada valor de um array, terminamos com um array aninhado.

const duplicate = (x) => [x, x];

[2, 3, 4].map(duplicate);
// → [[2, 2], [3, 3], [4, 4]]

Você pode então chamar flat no resultado para achatar o array:

[2, 3, 4].map(duplicate).flat(); // 🐌
// → [2, 2, 3, 3, 4, 4]

Como esse padrão é tão comum na programação funcional, agora há um método dedicado flatMap para ele.

[2, 3, 4].flatMap(duplicate); // 🚀
// → [2, 2, 3, 3, 4, 4]

flatMap é um pouco mais eficiente em comparação a fazer um map seguido de um flat separadamente.

Interessado em casos de uso para flatMap? Confira a explicação de Axel Rauschmayer.

Suporte a Array#{flat,flatMap}

Separadores Numéricos

· Leitura de 2 minutos
Mathias Bynens ([@mathias](https://twitter.com/mathias))

Literais numéricos grandes são difíceis para o olho humano interpretar rapidamente, especialmente quando há muitos dígitos repetidos:

1000000000000
1019436871.42

Para melhorar a legibilidade, uma nova funcionalidade da linguagem JavaScript permite sublinhados como separadores em literais numéricos. Assim, o exemplo acima agora pode ser reescrito para agrupar os dígitos por milhar, por exemplo:

`String.prototype.matchAll`

· Leitura de 3 minutos
Mathias Bynens ([@mathias](https://twitter.com/mathias))

É comum aplicar repetidamente a mesma expressão regular em uma string para obter todas as correspondências. Até certo ponto, isso já é possível hoje usando o método String#match.

Neste exemplo, encontramos todas as palavras que consistem apenas em dígitos hexadecimais e, em seguida, registramos cada correspondência:

const string = 'Números hex mágicos: DEADBEEF CAFE';
const regex = /\b\p{ASCII_Hex_Digit}+\b/gu;
for (const match of string.match(regex)) {
console.log(match);
}

// Saída:
//
// 'DEADBEEF'
// 'CAFE'

No entanto, isso só fornece os substrings que correspondem. Normalmente, você não quer apenas os substrings, mas também informações adicionais, como o índice de cada substring ou os grupos de captura dentro de cada correspondência.

Já é possível alcançar isso escrevendo seu próprio loop e rastreando os objetos de correspondência você mesmo, mas é um pouco chato e não muito prático:

const string = 'Números hex mágicos: DEADBEEF CAFE';
const regex = /\b\p{ASCII_Hex_Digit}+\b/gu;
let match;
while (match = regex.exec(string)) {
console.log(match);
}

// Saída:
//
// [ 'DEADBEEF', índice: 19, entrada: 'Números hex mágicos: DEADBEEF CAFE' ]
// [ 'CAFE', índice: 28, entrada: 'Números hex mágicos: DEADBEEF CAFE' ]

A nova API String#matchAll torna isso mais fácil do que nunca: agora você pode escrever um simples loop for-of para obter todos os objetos de correspondência.

const string = 'Números hex mágicos: DEADBEEF CAFE';
const regex = /\b\p{ASCII_Hex_Digit}+\b/gu;
for (const match of string.matchAll(regex)) {
console.log(match);
}

// Saída:
//
// [ 'DEADBEEF', índice: 19, entrada: 'Números hex mágicos: DEADBEEF CAFE' ]
// [ 'CAFE', índice: 28, entrada: 'Números hex mágicos: DEADBEEF CAFE' ]

String#matchAll é especialmente útil para expressões regulares com grupos de captura. Ele fornece todas as informações para cada correspondência individual, incluindo os grupos de captura.

const string = 'Repositórios favoritos do GitHub: tc39/ecma262 v8/v8.dev';
const regex = /\b(?<owner>[a-z0-9]+)\/(?<repo>[a-z0-9\.]+)\b/g;
for (const match of string.matchAll(regex)) {
console.log(`${match[0]} em ${match.index} com '${match.input}'`);
console.log(`→ proprietário: ${match.groups.owner}`);
console.log(`→ repositório: ${match.groups.repo}`);
}

`Intl.ListFormat`

· Leitura de 4 minutos
Mathias Bynens ([@mathias](https://twitter.com/mathias)) e Frank Yung-Fong Tang

Aplicações web modernas frequentemente usam listas compostas de dados dinâmicos. Por exemplo, um aplicativo visualizador de fotos pode exibir algo como:

Esta foto inclui Ada, Edith, e Grace.

Um jogo baseado em texto pode ter um tipo diferente de lista:

Escolha seu superpoder: invisibilidade, psicocinese, ou empatia.

Como cada idioma tem convenções de formatação de listas e palavras diferentes, implementar um formatador de listas localizado não é trivial. Isso não só exige uma lista de todas as palavras (como “e” ou “ou” nos exemplos acima) para cada idioma que você deseja suportar — além disso, você precisa codificar as convenções de formatação exatas para todos esses idiomas! O Unicode CLDR fornece esses dados, mas para usá-los em JavaScript, eles precisam ser integrados e enviados junto com o restante do código da biblioteca. Isso, infelizmente, aumenta o tamanho do pacote para essas bibliotecas, o que impacta negativamente os tempos de carregamento, o custo de análise/compilação e o consumo de memória.

Exportações de namespace de módulo

· Leitura de um minuto
Mathias Bynens ([@mathias](https://twitter.com/mathias))

Em módulos JavaScript, já era possível usar a seguinte sintaxe:

import * as utils from './utils.mjs';

No entanto, não existia uma sintaxe export simétrica… até agora:

export * as utils from './utils.mjs';

Isso é equivalente ao seguinte:

import * as utils from './utils.mjs';
export { utils };

Campos de classe públicos e privados

· Leitura de 5 minutos
Mathias Bynens ([@mathias](https://twitter.com/mathias))

Várias propostas expandem a sintaxe de classes JavaScript existente com novas funcionalidades. Este artigo explica a nova sintaxe de campos de classe públicos no V8 v7.2 e Chrome 72, assim como a futura sintaxe de campos de classe privados.

Aqui está um exemplo de código que cria uma instância de uma classe chamada IncreasingCounter:

const counter = new IncreasingCounter();
counter.value;
// registra 'Obtendo o valor atual!'
// → 0
counter.increment();
counter.value;
// registra 'Obtendo o valor atual!'
// → 1

Note que acessar o value executa algum código (isto é, registra uma mensagem) antes de retornar o resultado. Agora pergunte-se, como você implementaria esta classe em JavaScript? 🤔

Sintaxe de classe ES2015

Veja como IncreasingCounter poderia ser implementado usando a sintaxe de classe ES2015:

class IncreasingCounter {
constructor() {
this._count = 0;
}
get value() {
console.log('Obtendo o valor atual!');
return this._count;
}
increment() {
this._count++;
}
}

A classe instala o getter value e um método increment no protótipo. Mais interessantemente, a classe tem um construtor que cria uma propriedade de instância _count e define seu valor padrão como 0. Atualmente, costumamos usar o prefixo de sublinhado para indicar que _count não deve ser usado diretamente pelos consumidores da classe, mas isso é apenas uma convenção; não é realmente uma propriedade “privada” com semântica especial aplicada pela linguagem.

`Intl.RelativeTimeFormat`

· Leitura de 5 minutos
Mathias Bynens ([@mathias](https://twitter.com/mathias))

Aplicações web modernas frequentemente utilizam frases como “ontem”, “há 42 segundos” ou “em 3 meses” em vez de datas completas e carimbos temporais. Valores formatados como tempo relativo tornaram-se tão comuns que várias bibliotecas populares implementam funções utilitárias que os formatam de maneira localizada. (Exemplos incluem Moment.js, Globalize, e date-fns.)

`JSON.stringify` Bem-formado

· Leitura de um minuto
Mathias Bynens ([@mathias](https://twitter.com/mathias))

JSON.stringify anteriormente era especificado para retornar strings Unicode malformadas se a entrada contivesse algum surrogate solitário:

JSON.stringify('\uD800');
// → '"�"'

A proposta “JSON.stringify Bem-formado” altera JSON.stringify para que ele gere sequências de escape para surrogates solitários, tornando sua saída Unicode válido (e representável em UTF-8):

Módulos JavaScript

· Leitura de 21 minutos
Addy Osmani ([@addyosmani](https://twitter.com/addyosmani)) e Mathias Bynens ([@mathias](https://twitter.com/mathias))

Os módulos JavaScript agora estão suportados em todos os principais navegadores!

Este artigo explica como usar módulos JS, como implantá-los de forma responsável e como a equipe do Chrome está trabalhando para tornar os módulos ainda melhores no futuro.

O que são módulos JS?

Os módulos JS (também conhecidos como “módulos ES” ou “módulos do ECMAScript”) são uma nova grande funcionalidade, ou melhor, uma coleção de novas funcionalidades. Você pode ter usado um sistema de módulo JavaScript de terceiros antes. Talvez você tenha usado CommonJS como no Node.js, ou talvez AMD, ou algo do tipo. Todos esses sistemas de módulos têm uma coisa em comum: eles permitem que você importe e exporte funcionalidades.