A partir de 2016, o padrão ECMAScript adotou um ciclo de atualizações anuais, introduzindo incrementos graduais que modernizaram significativamente a linguagem JavaScript. Esta análise técnica foca nas adições mais relevantes entre as versões ES7 e ES10, demonstrando como essas funcionalidades resolvem problemas comuns de desenvolvimento e melhoram a legibilidade do código.
ES7 (ECMAScript 2016)
Verificação de existência em Arrays com includes()
Antes do ES7, a validação de presença de um elemento em um array dependia de indexOf() ou find(), que exigiam comparações verbosas ou falhavam ao detectar NaN. O método Array.prototype.includes() retorna um booleano direto e utiliza o algoritmo SameValueZero internamente, tratando corretamente valores especiais.
const itens = [10, 25, 30, NaN, -0];
// Verificação direta
console.log(itens.includes(25)); // true
console.log(itens.includes(NaN)); // true
console.log(itens.includes(-0)); // true
// Suporta índice inicial de busca
console.log(itens.includes(10, 1)); // false (inicia a busca a partir do índice 1)
Operador de Exponenciação (**)
A sintaxe ** fornece um atalho nativo para cálculo de potências, eliminando a dependência de Math.pow(). O operador segue a associatividade à direita, permitindo expressões encadeadas.
const base = 7;
const expoente = 3;
const resultadoDireto = base ** expoente; // 343
const equivalente = Math.pow(base, expoente); // 343
// Associatividade à direita: 2 ** (3 ** 2) = 2 ** 9 = 512
console.log(2 ** 3 ** 2); // 512
ES8 (ECMAScript 2017)
Async/Await para Fluxo Assíncrono Linear
A sintaxe async/await transforma operações baseadas em Promise em fluxo sequencial, reduzindo a complexidade visual causada por encadeamentos de .then(). Funções declaradas com async retornam implicitamente uma Promise, e await pausa a execução interna até que o objeto assíncrono se resolva.
// Abordagem com Promise (antiga)
fetchConfiguracao()
.then(config => {
return carregarUsuario(config.id);
})
.then(usuario => console.log(usuario))
.catch(erro => console.error(erro));
// Abordagem com Async/Await (moderna)
async function inicializarApp() {
try {
const config = await fetchConfiguracao();
const usuario = await carregarUsuario(config.id);
console.log(usuario);
} catch (erro) {
console.error('Falha na inicialização:', erro);
}
}
inicializarApp();
Iteração de Objetos: values() e entries()
Enquanto Object.keys() retorna apenas as chaves, as novas funções complementares retornam valores ou pares chave-valor, facilitando iterações com for...of.
const registro = { codigo: 88, nome: 'Módulo', ativo: true };
console.log(Object.values(registro));
// ["88", "Módulo", true]
console.log(Object.entries(registro));
// [["codigo", 88], ["nome", "Módulo"], ["ativo", true]]
// Iteração prática
for (const [chave, valor] of Object.entries(registro)) {
console.log(`${chave}: ${valor}`);
}
Preenchimento de Strings (padStart e padEnd)
Os métodos padStart() e padEnd() permitem alinhar strings a um comprimento específico, preenchendo com espaços ou outro caractere. São úteis para formatação de IDs, valores monetários ou relatórios.
const valorBruto = '45';
const valorFormatado = valorBruto.padStart(6, '0'); // "000045"
const etiqueta = 'OK';
const etiquetaCentralizada = etiqueta.padEnd(10, '.'); // "OK........"
Descritores de Propriedades para Cópias Seguras
Object.assign() não preserva getters e setters durante a cópia, convertendo-os em valores estáticos. Object.getOwnPropertyDescriptors() resolve isso ao capturar metadados completos das propriedades, permitindo réplicas exatas via Object.defineProperties().
const fonte = {
get status() { return 'ativo'; },
set status(val) { console.log(`Atualizado para ${val}`); }
};
// Object.assign perde o getter/setter
// Solução correta:
const destino = {};
Object.defineProperties(destino, Object.getOwnPropertyDescriptors(fonte));
console.log(destino.status); // "ativo" (chama o getter)
ES9 (ECMAScript 2018)
Iteração Assíncrona com for await...of
O loop for await...of consome iteradores assíncronos, aguardando a resolução de cada Promise antes de avançar para o próximo item. Isso garante processamento sequencial em fluxos de dados assíncronos.
async function gerarTarefas() {
yield new Promise(res => setTimeout(res, 200));
yield new Promise(res => setTimeout(res, 500));
yield new Promise(res => setTimeout(res, 100));
}
async function executarSequencial() {
for await (const tarefa of gerarTarefas()) {
console.log('Tarefa concluída em', Date.now());
}
}
executarSequencial();
Spread e Rest em Objetos
O operador spread (...) permite clonar ou mesclar objetos superficialmente. O operador rest coleta propriedades restantes em um novo objeto. Note que propriedades com chaves duplicadas são sobrescritas pela última ocorrência.
const padroes = { tema: 'escuro', idioma: 'pt-BR' };
const preferencias = { idioma: 'en-US', notificacoes: true };
const configuracao = { ...padroes, ...preferencias };
console.log(configuracao);
// { tema: 'escuro', idioma: 'en-US', notificacoes: true }
// Uso de rest
const { idioma, ...restoConfig } = configuracao;
console.log(restoConfig); // { tema: 'escuro', notificacoes: true }
Promise.prototype.finally()
O método finally() executa um callback independentemente do estado da Promise (resolvida ou rejeitada). Ideal para limpeza de interfaces, como ocultar indicadores de carregamento.
carregarDados()
.then(response => processar(response))
.catch(erro => registrarErro(erro))
.finally(() => {
document.getElementById('loader').classList.remove('visivel');
});
Atualizações em Expressões Regulares
- Flag s (dotAll): Faz o ponto (
.) corresponder a quebras de linha. - Named Capture Groups: Permite nomear grupos para facilitar a extração.
- Lookbehind: Afirmação posterior (
(?<=...)) que verifica conteúdo antecedente sem capturá-lo. - Unicode Property Escapes: Correspondência baseada em categorias Unicode (
\p{...}).
// Named groups e Lookbehind
const texto = 'ID: 5543 | Usuário: joao';
const regex = /(?<=\| \w+: )(\w+)/;
const match = texto.match(regex);
console.log(match[0]); // "joao"
// Unicode
const emoji = '🚀';
console.log(/\p{Emoji}/u.test(emoji)); // true
ES10 (ECMAScript 2019)
Array.prototype.flat() e flatMap()
flat() reduz a profundidade de arrays aninhados. O parâmetro de profundidade define quantos níveis serão recursivamente mesclados. flatMap() combina mapeamento e aplatamento em uma única iteração, equivalente a map().flat(1).
const categorias = [['A'], ['B', ['C', 'D']], ['E']];
console.log(categorias.flat());
// ["A", "B", ["C", "D"], "E"]
console.log(categorias.flat(2));
// ["A", "B", "C", "D", "E"]
const numeros = [2, 4, 6];
const expandido = numeros.flatMap(n => [n, n * 10]);
console.log(expandido); // [2, 20, 4, 40, 6, 60]
Object.fromEntries()
Inverso de Object.entries(), converte listas de pares chave-valor em objetos. Facilita transformações funcionais em estruturas de dados.
const dados = [['chave1', 10], ['chave2', 20]];
const objeto = Object.fromEntries(dados);
console.log(objeto); // { chave1: 10, chave2: 20 }
// Filtragem e reconstrução
const produto = { preco: 150, estoque: 0, visivel: true };
const disponiveis = Object.fromEntries(
Object.entries(produto).filter(([_, valor]) => valor > 0)
);
console.log(disponiveis); // { preco: 150, visivel: true }
Remoção de Espaços: trimStart() e trimEnd()
Alternativas diretas a regex para limpeza de strings, removendo caracteres em branco apenas do início ou do final.
const entrada = ' 42.50 ';
console.log(entrada.trimStart()); // "42.50 "
console.log(entrada.trimEnd()); // " 42.50"
String.prototype.matchAll()
Retorna um iterader com todas as correspondências de uma regex global, incluindo informações de grupos e índices, sem a necessidade de loops while manuais com exec().
const log = 'Erro: E404 | Aviso: W301 | Sucesso: 200';
const regex = /([A-Z]\d{3})/g;
for (const match of log.matchAll(regex)) {
console.log(`Código: ${match[1]} na posição ${match.index}`);
}
Optional Catch Binding
A cláusula catch torna-se opcional. Quando o erro não precisa ser processado ou logado, o parâmetro pode ser omitido, reduzindo variáveis inutilizadas no escopo.
try {
operacaoCritica();
} catch {
console.warn('Operação falhou, continuando...');
}
BigInt
Nova primitiva para inteiros de precisão arbitrária. Resolve limitações do tipo Number (64-bit float), que perde precisão acima de Number.MAX_SAFE_INTEGER (2^53 - 1). Criação via sufixo n ou construtor BigInt().
const valorGrande = 9007199254740992n;
const soma = valorGrande + 1n;
console.log(typeof soma); // "bigint"
console.log(valorGrande === BigInt(valorGrande.toString())); // true
// Operações mistas geram TypeError
// console.log(10n + 5); // Erro! Use 10n + 5n
Symbol.prototype.description
Propriedade de leitura direta para acessar a descrição interna de um Symbol, sem necessidade de converter para string.
const token = Symbol('acesso_api');
console.log(token.description); // "acesso_api"
Function.prototype.toString() Prseerva Formatação
A partir do ES10, o método retorna o código fonte exato da função, incluindo espaçamento, quebras de linha e comentários, diferente do comportamento anterior que removia formatação excessiva.
function calcular(base, taxa) {
// Aplica desconto
return base - (base * taxa);
}
console.log(calcular.toString());
/* Retorna exatamente:
function calcular(base, taxa) {
// Aplica desconto
return base - (base * taxa);
}
*/