12k
All articles

O Que Há de Novo no ECMAScript 2026

ES2026 traz sete recursos do JavaScript: Array.fromAsync, Math.sumPrecise, métodos base64 e hex de Uint8Array, acesso ao texto fonte em JSON.parse e getOrInsert.

OpenReplay Team
OpenReplay Team
O Que Há de Novo no ECMAScript 2026

A Ecma International aprovou a especificação da linguagem ECMAScript 2026 em 30 de junho de 2026, e ela contém exatamente sete novos recursos: Array.fromAsync, Error.isError, Math.sumPrecise, métodos base64 e hex em Uint8Array, Iterator.concat, acesso ao texto-fonte em JSON.parse e getOrInsert em Map e WeakMap.

Todos os anos esses métodos chegam discretamente, e a maioria de nós os conhece no dia em que apaga um helper que carregava havia anos. Desta vez, provavelmente será um utilitário de base64.

Se você pesquisou sobre ES2026 recentemente, provavelmente encontrou listas que discordam entre si, várias delas incluindo Temporal ou a palavra-chave using. Essas listas estão erradas, e este artigo explica o motivo, para em seguida percorrer cada um dos sete recursos que realmente foram lançados: o problema que resolvem, o código que substituem e a única linha que passa a ocupar o seu lugar.

O registro oficial é o anúncio de aprovação da Ecma, que confirma o ES2026 como a 17ª edição do ECMA-262, e a tabela de propostas finalizadas do TC39, na qual exatamente sete linhas trazem o Ano de Publicação Esperado como 2026.

Pontos Principais

  • O ES2026 foi aprovado em 30 de junho de 2026 e adiciona exatamente sete recursos; Temporal e Explicit Resource Management não estão entre eles.
  • Math.sumPrecise([1e17, 1, -1e17]) retorna 1, enquanto os mesmos valores somados com reduce retornam 0.
  • Uint8Array ganha os métodos nativos toBase64(), toHex(), fromBase64() e fromHex(), eliminando uma dependência comum.
  • O reviver de JSON.parse agora recebe um terceiro argumento que expõe o texto-fonte bruto, e JSON.rawJSON() resolve o lado do stringify, permitindo que BigInts façam o round-trip completo em JSON.
  • Map.prototype.getOrInsert(key, value) retorna o valor existente quando a chave já está presente; ele só insere o seu valor padrão quando a chave está ausente.

O Que Ficou de Fora do ES2026?

Temporal e Explicit Resource Management (using / await using) não fazem parte do ES2026. Na lista de propostas finalizadas do TC39, ambos trazem o Ano de Publicação Esperado como 2027, junto com Atomics.pause e Joint Iteration. Todos os quatro alcançaram o estágio 4, a etapa final do processo do TC39, após o prazo limite do ES2026. A cobertura anterior à aprovação, no fim de 2025, previu amplamente que eles chegariam em 2026, e daí vêm as listas conflitantes de recursos. A verificação que qualquer pessoa pode fazer: filtrar a coluna Ano de Publicação Esperado na tabela de propostas finalizadas. Sete propostas indicam 2026, e nenhuma delas é Temporal.

Array.fromAsync

Array.fromAsync recebe um iterador assíncrono e devolve um array, encapsulado em uma promise. Ele também aceita um iterador síncrono cujos valores são promises, um objeto array-like e uma função de mapeamento opcional, da mesma forma que Array.from. Até agora, coletar um iterador assíncrono significava um laço for await empurrando valores para um array mutável:

const arr = [];
for await (const n of asyncGen(1, 3)) {
  arr.push(`page ${n}`);
}

O mesmo resultado agora é uma única expressão:

const arr = await Array.fromAsync(asyncGen(1, 3), (n) => `page ${n}`);
// [ 'page 1', 'page 2', 'page 3' ]

Error.isError

Error.isError(value) retorna true apenas quando o valor capturado é um objeto Error genuíno. O JavaScript permite lançar qualquer coisa, e instanceof Error engana quando valores cruzam fronteiras de iframe ou de realm, porque cada realm tem seu próprio construtor Error. Um bloco catch condicionado a instanceof Error pode silenciosamente ignorar o ramo que renderiza uma mensagem útil, e replays de sessão dessa classe de bug mostram um padrão familiar: o usuário travado em uma tela que não reporta nada enquanto um throw real aconteceu por baixo. Error.isError fecha essa lacuna.

try {
  throw new Error("session upload failed");
} catch (error) {
  Error.isError(error); // true
}

try {
  throw "session upload failed";
} catch (error) {
  Error.isError(error); // false
}

Math.sumPrecise

Math.sumPrecise soma um iterável de números sem acumular erro de ponto flutuante nos resultados intermediários. Uma cadeia de reduce soma par a par, então grandezas grandes e pequenas se cancelam de forma problemática:

const values = [1e17, 1, -1e17];

values.reduce((a, b) => a + b, 0); // 0
Math.sumPrecise(values);           // 1

A versão com reduce perde o 1 por completo. Além da precisão, isso também aposenta o reducer de soma como boilerplate.

Uint8Array toBase64, toHex, fromBase64 e fromHex

O ES2026 dá ao Uint8Array os métodos nativos toBase64() e toHex(), além dos estáticos Uint8Array.fromBase64() e Uint8Array.fromHex() para decodificação. A conversão de binário para texto antes significava incluir uma biblioteca ou implementar a codificação à mão; essa é uma dependência que a maioria das bases de código pode agora apagar.

const value = new Uint8Array([79, 112, 101, 110, 82, 101, 112, 108, 97, 121]);

const valueBase64 = value.toBase64(); // 'T3BlblJlcGxheQ=='
const decoded = Uint8Array.fromBase64(valueBase64);

new TextDecoder().decode(decoded); // 'OpenReplay'

Iterator.concat

Iterator.concat() encadeia iteradores em sequência. Até agora, a única forma de fazer isso era um generator escrito à mão que percorria cada fonte e delegava com yield*:

function* combine(...iterators) {
  for (const source of iterators) {
    yield* source;
  }
}

Agora é uma única chamada, e arrays simples de valores podem se encaixar entre os iteradores. O [300] no meio abaixo é um array simples e não precisa ser envolvido em Iterator.from.

const iOne = Iterator.from([100, 200]);
const iTwo = Iterator.from([400, 500]);

const combined = Iterator.concat(iOne, [300], iTwo);
Array.from(combined); // [ 100, 200, 300, 400, 500 ]

Acesso ao Texto-Fonte em JSON.parse

O round-trip de JSON em JavaScript era lossy nas duas direções antes do ES2026. Fazer o parse de um literal inteiro grande o arredonda silenciosamente, e serializar um BigInt lança erro:

JSON.parse("9007199254740993");   // 9007199254740992
JSON.stringify(9007199254740993n); // TypeError: Do not know how to serialize a BigInt

A proposta de acesso ao texto-fonte em JSON.parse corrige os dois lados. JSON.parse agora entrega ao seu reviver um terceiro argumento contendo o texto source intacto, que você pode converter por conta própria sem perder dígitos. No lado do stringify, JSON.rawJSON() permite que um replacer emita um valor literalmente:

JSON.parse("9007199254740993", (key, value, { source }) => BigInt(source));
// 9007199254740993n

JSON.stringify(9007199254740993n, (key, value) => JSON.rawJSON(value));
// 9007199254740993

Um BigInt agora pode sobreviver a um round-trip de JSON sem perder dígitos nem lançar erro.

Map.prototype.getOrInsert e WeakMap.prototype.getOrInsert

A proposta Upsert traz getOrInsert(key, value) tanto para Map quanto para WeakMap, de modo que você não precisa mais chamar has() e depois set(). A semântica importa: getOrInsert retorna o valor existente quando a chave já está presente. Ele só insere, e só retorna o seu valor padrão, quando a chave está ausente.

const limits = new Map();
limits.set("uploads", 25);

limits.getOrInsert("exports", 10);   // 10  (inserido)
limits.getOrInsert("uploads", 100);  // 25  (o valor existente prevalece)

Note que 100 é descartado porque "uploads" já estava definido. Trate o segundo argumento como um valor padrão, não como uma sobrescrita.

O Que Você Pode Apagar Agora?

O ES2026 é uma release de limpeza: cada um dos sete recursos aposenta um padrão que você provavelmente tem em produção hoje. A dependência do helper de base64, o reducer de soma, os blocos de guarda com has() seguido de set(), o generator de concatenação com yield* e o laço de coleta com for await todos têm substitutos nativos diretos. A disponibilidade em runtime varia conforme o engine, então consulte a referência de objetos nativos padrão do MDN para o panorama atual de suporte de cada método antes de descartar polyfills. Depois comece pela vitória mais fácil na sua base de código, que para a maioria dos times é trocar as verificações de existência em Map por getOrInsert.

Perguntas Frequentes

Qual é a diferença entre Array.fromAsync e Promise.all?

Array.fromAsync aguarda os valores sequencialmente, um a um, e aceita iteráveis assíncronos, iteráveis síncronos que produzem promises e objetos array-like. Promise.all executa um iterável de promises de forma concorrente e rejeita assim que qualquer promise for rejeitada. Use Promise.all para trabalho paralelo e Array.fromAsync quando a ordem importa ou quando a fonte é um iterador assíncrono. Ambos retornam uma promise que resolve para um array.

Error.isError retorna true para TypeError e outras subclasses de Error?

Sim. Error.isError retorna true para todas as subclasses genuínas de Error, incluindo TypeError, RangeError, SyntaxError e classes personalizadas que estendem Error, porque os engines verificam uma marca interna que os erros reais carregam, em vez da cadeia de protótipos. Nos navegadores, uma DOMException também conta como erro real. Ele retorna false para objetos que apenas imitam erros, como objetos simples com uma propriedade message ou objetos criados com Object.create(Error.prototype).

Uint8Array.prototype.toBase64 pode produzir base64 URL-safe?

Sim. toBase64 aceita um objeto de opções com a propriedade alphabet definida como 'base64' (o padrão, usando + e /) ou 'base64url' (usando - e _), além de um booleano omitPadding que remove os caracteres = finais. Uint8Array.fromBase64 aceita a mesma opção alphabet e uma opção lastChunkHandling ('loose', 'strict' ou 'stop-before-partial') que controla como um bloco final com menos de quatro caracteres é decodificado.

Como evito calcular um valor padrão custoso com getOrInsert?

Use getOrInsertComputed(key, callback), que a mesma proposta Upsert adiciona a Map e WeakMap. Ele chama o callback para produzir o valor apenas quando a chave está ausente, então insere e retorna o resultado; quando a chave já existe, o callback nunca é executado e o valor existente é retornado. O getOrInsert simples sempre avalia seu segundo argumento antes da chamada, mesmo quando a chave já está presente.

Open-source session replay

Complete picture for complete understanding

Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.