Voltar para o Blog

ECMAScript 2025: As Novas Features do JavaScript Que Voce Precisa Conhecer

Olá HaWkers, o ECMAScript 2025 trouxe uma das atualizações mais substanciais dos últimos anos para o JavaScript. Com novos Iterator helpers, métodos de Set, importação direta de JSON e melhorias em Promises, a linguagem continua evoluindo para atender às necessidades dos desenvolvedores modernos.

Vamos explorar cada uma dessas novidades com exemplos práticos que você pode começar a usar hoje mesmo.

Iterator Helpers: A Grande Estrela

A adição mais aguardada do ES2025 são os Iterator helpers. Finalmente, podemos usar métodos como map, filter e reduce diretamente em iteradores, sem precisar converter para arrays.

Por Que Isso Importa

Antes, trabalhar com iteradores exigia conversão constante:

// Antes do ES2025 - Ineficiente para grandes conjuntos
function* gerarNumeros(limite) {
  for (let i = 0; i < limite; i++) {
    yield i;
  }
}

// Precisava converter para array primeiro
const numeros = [...gerarNumeros(1000000)];
const pares = numeros.filter(n => n % 2 === 0);
const dobrados = pares.map(n => n * 2);
const soma = dobrados.reduce((acc, n) => acc + n, 0);
// Problema: Cria 3 arrays intermediarios na memoria

Agora com Iterator helpers:

// ES2025 - Lazy evaluation, sem arrays intermediarios
function* gerarNumeros(limite) {
  for (let i = 0; i < limite; i++) {
    yield i;
  }
}

const resultado = gerarNumeros(1000000)
  .filter(n => n % 2 === 0)
  .map(n => n * 2)
  .reduce((acc, n) => acc + n, 0);

// Processa item por item, sem criar arrays intermediarios
console.log(resultado);

Metodos Disponiveis

O objeto Iterator agora possui métodos funcionais nativos:

// map - Transforma cada elemento
const iterator = [1, 2, 3].values();
const dobrados = iterator.map(x => x * 2);
console.log([...dobrados]); // [2, 4, 6]

// filter - Filtra elementos
const numeros = [1, 2, 3, 4, 5].values();
const pares = numeros.filter(x => x % 2 === 0);
console.log([...pares]); // [2, 4]

// take - Pega os primeiros N elementos
const infinito = function* () {
  let i = 0;
  while (true) yield i++;
}();
const primeiros = infinito.take(5);
console.log([...primeiros]); // [0, 1, 2, 3, 4]

// drop - Pula os primeiros N elementos
const lista = [1, 2, 3, 4, 5].values();
const semPrimeiros = lista.drop(2);
console.log([...semPrimeiros]); // [3, 4, 5]

// flatMap - Map + flatten
const aninhado = [[1, 2], [3, 4]].values();
const achatado = aninhado.flatMap(arr => arr.values());
console.log([...achatado]); // [1, 2, 3, 4]

Caso de Uso Real: Processamento de Dados

// Processando linhas de um arquivo grande com lazy evaluation
async function* lerLinhas(arquivo) {
  const reader = arquivo.getReader();
  const decoder = new TextDecoder();
  let buffer = '';

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    buffer += decoder.decode(value, { stream: true });
    const linhas = buffer.split('\n');
    buffer = linhas.pop(); // Guarda linha incompleta

    for (const linha of linhas) {
      yield linha;
    }
  }

  if (buffer) yield buffer;
}

// Usando iterator helpers para processar
const csvProcessado = lerLinhas(arquivoGrande)
  .filter(linha => linha.trim() !== '')
  .filter(linha => !linha.startsWith('#'))
  .map(linha => linha.split(','))
  .filter(campos => campos.length === 4)
  .map(([nome, email, idade, cidade]) => ({
    nome: nome.trim(),
    email: email.trim(),
    idade: parseInt(idade),
    cidade: cidade.trim()
  }))
  .filter(pessoa => pessoa.idade >= 18);

// Apenas 100 registros, sem carregar arquivo inteiro
const primeiros100 = csvProcessado.take(100);

Novos Metodos de Set

Os Sets JavaScript finalmente receberam métodos que já existiam em outras linguagens há décadas.

Operacoes de Conjunto

const setA = new Set([1, 2, 3, 4, 5]);
const setB = new Set([4, 5, 6, 7, 8]);

// union - Todos os elementos de ambos os conjuntos
const uniao = setA.union(setB);
console.log([...uniao]); // [1, 2, 3, 4, 5, 6, 7, 8]

// intersection - Elementos comuns
const intersecao = setA.intersection(setB);
console.log([...intersecao]); // [4, 5]

// difference - Elementos em A que nao estao em B
const diferenca = setA.difference(setB);
console.log([...diferenca]); // [1, 2, 3]

// symmetricDifference - Elementos exclusivos de cada conjunto
const diferencaSimetrica = setA.symmetricDifference(setB);
console.log([...diferencaSimetrica]); // [1, 2, 3, 6, 7, 8]

// isSubsetOf - Verifica se A esta contido em B
const subset = new Set([4, 5]);
console.log(subset.isSubsetOf(setA)); // true
console.log(subset.isSubsetOf(setB)); // true

// isSupersetOf - Verifica se A contem B
console.log(setA.isSupersetOf(subset)); // true

// isDisjointFrom - Verifica se nao ha elementos comuns
const setC = new Set([10, 11, 12]);
console.log(setA.isDisjointFrom(setC)); // true
console.log(setA.isDisjointFrom(setB)); // false

Aplicacao Pratica: Sistema de Permissoes

class SistemaPermissoes {
  constructor() {
    this.roles = new Map();
  }

  definirRole(nome, permissoes) {
    this.roles.set(nome, new Set(permissoes));
  }

  permissoesUsuario(rolesUsuario) {
    return rolesUsuario.reduce((acc, role) => {
      const permissoesRole = this.roles.get(role) || new Set();
      return acc.union(permissoesRole);
    }, new Set());
  }

  verificarAcesso(rolesUsuario, permissoesNecessarias) {
    const permissoesUsuario = this.permissoesUsuario(rolesUsuario);
    const necessarias = new Set(permissoesNecessarias);

    // Verifica se usuario tem todas as permissoes necessarias
    return necessarias.isSubsetOf(permissoesUsuario);
  }

  permissoesFaltantes(rolesUsuario, permissoesNecessarias) {
    const permissoesUsuario = this.permissoesUsuario(rolesUsuario);
    const necessarias = new Set(permissoesNecessarias);

    // Retorna permissoes que o usuario nao tem
    return necessarias.difference(permissoesUsuario);
  }
}

// Uso
const sistema = new SistemaPermissoes();

sistema.definirRole('admin', ['criar', 'ler', 'atualizar', 'deletar', 'gerenciar_usuarios']);
sistema.definirRole('editor', ['criar', 'ler', 'atualizar']);
sistema.definirRole('leitor', ['ler']);

const usuario = ['editor', 'leitor'];
const permissoesNecessarias = ['criar', 'deletar'];

console.log(sistema.verificarAcesso(usuario, permissoesNecessarias)); // false
console.log([...sistema.permissoesFaltantes(usuario, permissoesNecessarias)]); // ['deletar']

Import JSON Diretamente

Agora podemos importar arquivos JSON diretamente como módulos ES, sem necessidade de fetch ou require.

// config.json
// {
//   "apiUrl": "https://api.exemplo.com",
//   "timeout": 5000,
//   "maxRetries": 3
// }

// Antes - Precisava de fetch ou fs
// const config = await fetch('./config.json').then(r => r.json());

// ES2025 - Import direto com assertion
import config from './config.json' with { type: 'json' };

console.log(config.apiUrl); // https://api.exemplo.com
console.log(config.timeout); // 5000

Casos de Uso

// Importar dados estaticos
import traducoes from './lang/pt-BR.json' with { type: 'json' };
import rotas from './routes.json' with { type: 'json' };
import schema from './validation-schema.json' with { type: 'json' };

// Dynamic import tambem funciona
const locale = 'en-US';
const mensagens = await import(`./lang/${locale}.json`, {
  with: { type: 'json' }
});

Promise.try: Simplificando Cadeias de Promises

O novo método Promise.try permite iniciar uma cadeia de Promises de forma mais limpa, tratando tanto funções síncronas quanto assíncronas.

// Antes - Precisava de workarounds
function processarDados(dados) {
  // Pode lancar excecao sincrona
  const validados = validarDados(dados);

  // Pode retornar Promise
  return salvarNoBanco(validados);
}

// Workaround antigo
Promise.resolve()
  .then(() => processarDados(dados))
  .then(resultado => console.log(resultado))
  .catch(erro => console.error(erro));

// ES2025 - Mais limpo
Promise.try(() => processarDados(dados))
  .then(resultado => console.log(resultado))
  .catch(erro => console.error(erro));

Por Que Promise.try e Util

// Funcao que pode ser sincrona ou assincrona
function buscarUsuario(id) {
  // Validacao sincrona pode lancar erro
  if (!id || typeof id !== 'number') {
    throw new Error('ID invalido');
  }

  // Cache sincrono
  if (cache.has(id)) {
    return cache.get(id); // Retorno sincrono
  }

  // Busca assincrona
  return fetch(`/api/users/${id}`).then(r => r.json());
}

// Promise.try trata ambos os casos uniformemente
Promise.try(() => buscarUsuario(userId))
  .then(usuario => renderizar(usuario))
  .catch(erro => mostrarErro(erro));

// Equivalente a:
// new Promise(resolve => resolve(buscarUsuario(userId)))
//   .then(...)
//   .catch(...);

Float16Array: Novo Typed Array

Para aplicações de machine learning e processamento de dados que precisam de eficiência de memória, o novo Float16Array oferece números de ponto flutuante de 16 bits.

// Float16Array usa metade da memoria de Float32Array
const dados16 = new Float16Array([1.5, 2.5, 3.5, 4.5]);
const dados32 = new Float32Array([1.5, 2.5, 3.5, 4.5]);

console.log(dados16.byteLength); // 8 bytes
console.log(dados32.byteLength); // 16 bytes

// Util para ML onde precisao total nao e necessaria
function criarTensorEficiente(dimensoes, valores) {
  const total = dimensoes.reduce((a, b) => a * b, 1);
  const dados = new Float16Array(total);

  for (let i = 0; i < valores.length; i++) {
    dados[i] = valores[i];
  }

  return {
    shape: dimensoes,
    data: dados,
    dtype: 'float16'
  };
}

const tensor = criarTensorEficiente([2, 3], [1, 2, 3, 4, 5, 6]);

Melhorias em Regular Expressions

O ES2025 também trouxe melhorias para expressões regulares, incluindo o modificador de flag inline.

// Modifier flag inline - Ativa/desativa flags em partes da regex
const regex = /(?i:hello) world/;

// (?i:...) torna apenas "hello" case-insensitive
console.log(regex.test('HELLO world')); // true
console.log(regex.test('hello WORLD')); // false (world precisa ser minusculo)

// Util para padroes complexos
const emailRegex = /(?i:[a-z0-9._%+-]+)@(?i:[a-z0-9.-]+)\.(?i:[a-z]{2,})/;

Suporte nos Navegadores

A maioria das features do ES2025 já está disponível nos navegadores modernos:

Iterator Helpers:

  • Chrome 122+
  • Firefox 131+
  • Safari 17.4+

Set Methods:

  • Chrome 122+
  • Firefox 127+
  • Safari 17+

JSON Modules:

  • Chrome 123+
  • Firefox 135+
  • Safari 17.2+

Promise.try:

  • Chrome 128+
  • Firefox 132+
  • Safari 18+

Para projetos que precisam suportar navegadores mais antigos, utilize transpiladores como Babel com os plugins apropriados.

Migrando Seu Codigo

Aqui está um checklist para começar a usar as novas features:

1. Atualize suas ferramentas:

npm update typescript @babel/core @babel/preset-env

2. Configure o target do TypeScript:

{
  "compilerOptions": {
    "target": "ES2025",
    "lib": ["ES2025", "DOM"]
  }
}

3. Adicione polyfills se necessário:

npm install core-js@latest
// Importe apenas os polyfills necessarios
import 'core-js/actual/iterator';
import 'core-js/actual/set';
import 'core-js/actual/promise/try';

O ECMAScript 2025 representa um passo significativo na evolução do JavaScript, trazendo features que tornam o código mais expressivo e eficiente. Se você quer aprofundar seus conhecimentos em JavaScript moderno, recomendo dar uma olhada no artigo sobre Web Workers: Performance com Threads onde você aprenderá técnicas avançadas de otimização.

Bora pra cima! 🦅

Comentários (0)

Esse artigo ainda não possui comentários 😢. Seja o primeiro! 🚀🦅

Adicionar comentário